github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/fvm/transactionVerifier_test.go (about)

     1  package fvm_test
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/stretchr/testify/require"
     7  
     8  	"github.com/onflow/flow-go/fvm"
     9  	"github.com/onflow/flow-go/fvm/crypto"
    10  	"github.com/onflow/flow-go/fvm/environment"
    11  	"github.com/onflow/flow-go/fvm/errors"
    12  	"github.com/onflow/flow-go/fvm/storage"
    13  	"github.com/onflow/flow-go/fvm/storage/testutils"
    14  	"github.com/onflow/flow-go/model/flow"
    15  	"github.com/onflow/flow-go/utils/unittest"
    16  )
    17  
    18  func TestTransactionVerification(t *testing.T) {
    19  	txnState := testutils.NewSimpleTransaction(nil)
    20  	accounts := environment.NewAccounts(txnState)
    21  
    22  	// create 2 accounts
    23  	address1 := flow.HexToAddress("1234")
    24  	privKey1, err := unittest.AccountKeyDefaultFixture()
    25  	require.NoError(t, err)
    26  
    27  	err = accounts.Create([]flow.AccountPublicKey{privKey1.PublicKey(1000)}, address1)
    28  	require.NoError(t, err)
    29  
    30  	address2 := flow.HexToAddress("1235")
    31  	privKey2, err := unittest.AccountKeyDefaultFixture()
    32  	require.NoError(t, err)
    33  
    34  	err = accounts.Create([]flow.AccountPublicKey{privKey2.PublicKey(1000)}, address2)
    35  	require.NoError(t, err)
    36  
    37  	tx := &flow.TransactionBody{}
    38  
    39  	run := func(
    40  		body *flow.TransactionBody,
    41  		ctx fvm.Context,
    42  		txn storage.TransactionPreparer,
    43  	) error {
    44  		executor := fvm.Transaction(body, 0).NewExecutor(ctx, txn)
    45  		err := fvm.Run(executor)
    46  		require.NoError(t, err)
    47  		return executor.Output().Err
    48  	}
    49  
    50  	t.Run("duplicated authorization signatures", func(t *testing.T) {
    51  
    52  		sig := flow.TransactionSignature{
    53  			Address:     address1,
    54  			SignerIndex: 0,
    55  			KeyIndex:    0,
    56  		}
    57  
    58  		tx.SetProposalKey(address1, 0, 0)
    59  		tx.SetPayer(address1)
    60  
    61  		tx.PayloadSignatures = []flow.TransactionSignature{sig, sig}
    62  
    63  		ctx := fvm.NewContext(
    64  			fvm.WithAuthorizationChecksEnabled(true),
    65  			fvm.WithAccountKeyWeightThreshold(1000),
    66  			fvm.WithSequenceNumberCheckAndIncrementEnabled(false),
    67  			fvm.WithTransactionBodyExecutionEnabled(false))
    68  		err = run(tx, ctx, txnState)
    69  		require.ErrorContains(
    70  			t,
    71  			err,
    72  			"duplicate signatures are provided for the same key")
    73  	})
    74  	t.Run("duplicated authorization and envelope signatures", func(t *testing.T) {
    75  
    76  		sig := flow.TransactionSignature{
    77  			Address:     address1,
    78  			SignerIndex: 0,
    79  			KeyIndex:    0,
    80  		}
    81  
    82  		tx.SetProposalKey(address1, 0, 0)
    83  		tx.SetPayer(address1)
    84  
    85  		tx.PayloadSignatures = []flow.TransactionSignature{sig}
    86  		tx.EnvelopeSignatures = []flow.TransactionSignature{sig}
    87  
    88  		ctx := fvm.NewContext(
    89  			fvm.WithAuthorizationChecksEnabled(true),
    90  			fvm.WithAccountKeyWeightThreshold(1000),
    91  			fvm.WithSequenceNumberCheckAndIncrementEnabled(false),
    92  			fvm.WithTransactionBodyExecutionEnabled(false))
    93  		err = run(tx, ctx, txnState)
    94  		require.ErrorContains(
    95  			t,
    96  			err,
    97  			"duplicate signatures are provided for the same key")
    98  	})
    99  
   100  	t.Run("invalid envelope signature", func(t *testing.T) {
   101  		tx.SetProposalKey(address1, 0, 0)
   102  		tx.SetPayer(address2)
   103  
   104  		// assign a valid payload signature
   105  		hasher1, err := crypto.NewPrefixedHashing(privKey1.HashAlgo, flow.TransactionTagString)
   106  		require.NoError(t, err)
   107  		validSig, err := privKey1.PrivateKey.Sign(tx.PayloadMessage(), hasher1) // valid signature
   108  		require.NoError(t, err)
   109  
   110  		sig1 := flow.TransactionSignature{
   111  			Address:     address1,
   112  			SignerIndex: 0,
   113  			KeyIndex:    0,
   114  			Signature:   validSig,
   115  		}
   116  
   117  		sig2 := flow.TransactionSignature{
   118  			Address:     address2,
   119  			SignerIndex: 0,
   120  			KeyIndex:    0,
   121  			// invalid signature
   122  		}
   123  
   124  		tx.PayloadSignatures = []flow.TransactionSignature{sig1}
   125  		tx.EnvelopeSignatures = []flow.TransactionSignature{sig2}
   126  
   127  		ctx := fvm.NewContext(
   128  			fvm.WithAuthorizationChecksEnabled(true),
   129  			fvm.WithAccountKeyWeightThreshold(1000),
   130  			fvm.WithSequenceNumberCheckAndIncrementEnabled(false),
   131  			fvm.WithTransactionBodyExecutionEnabled(false))
   132  		err = run(tx, ctx, txnState)
   133  		require.Error(t, err)
   134  		require.True(t, errors.IsInvalidEnvelopeSignatureError(err))
   135  	})
   136  
   137  	t.Run("invalid payload signature", func(t *testing.T) {
   138  		tx.SetProposalKey(address1, 0, 0)
   139  		tx.SetPayer(address2)
   140  
   141  		sig1 := flow.TransactionSignature{
   142  			Address:     address1,
   143  			SignerIndex: 0,
   144  			KeyIndex:    0,
   145  			// invalid signature
   146  		}
   147  
   148  		// assign a valid envelope signature
   149  		hasher2, err := crypto.NewPrefixedHashing(privKey2.HashAlgo, flow.TransactionTagString)
   150  		require.NoError(t, err)
   151  		validSig, err := privKey2.PrivateKey.Sign(tx.EnvelopeMessage(), hasher2) // valid signature
   152  		require.NoError(t, err)
   153  
   154  		sig2 := flow.TransactionSignature{
   155  			Address:     address2,
   156  			SignerIndex: 0,
   157  			KeyIndex:    0,
   158  			Signature:   validSig,
   159  		}
   160  
   161  		tx.PayloadSignatures = []flow.TransactionSignature{sig1}
   162  		tx.EnvelopeSignatures = []flow.TransactionSignature{sig2}
   163  
   164  		ctx := fvm.NewContext(
   165  			fvm.WithAuthorizationChecksEnabled(true),
   166  			fvm.WithAccountKeyWeightThreshold(1000),
   167  			fvm.WithSequenceNumberCheckAndIncrementEnabled(false),
   168  			fvm.WithTransactionBodyExecutionEnabled(false))
   169  		err = run(tx, ctx, txnState)
   170  		require.Error(t, err)
   171  		require.True(t, errors.IsInvalidPayloadSignatureError(err))
   172  	})
   173  
   174  	t.Run("invalid payload and envelope signatures", func(t *testing.T) {
   175  		// TODO: this test expects a Payload error but should be updated to expect en Envelope error.
   176  		// The test should be updated once the FVM updates the order of validating signatures:
   177  		// envelope needs to be checked first and payload later.
   178  		tx.SetProposalKey(address1, 0, 0)
   179  		tx.SetPayer(address2)
   180  
   181  		sig1 := flow.TransactionSignature{
   182  			Address:     address1,
   183  			SignerIndex: 0,
   184  			KeyIndex:    0,
   185  			// invalid signature
   186  		}
   187  
   188  		sig2 := flow.TransactionSignature{
   189  			Address:     address2,
   190  			SignerIndex: 0,
   191  			KeyIndex:    0,
   192  			// invalid signature
   193  		}
   194  
   195  		tx.PayloadSignatures = []flow.TransactionSignature{sig1}
   196  		tx.EnvelopeSignatures = []flow.TransactionSignature{sig2}
   197  
   198  		ctx := fvm.NewContext(
   199  			fvm.WithAuthorizationChecksEnabled(true),
   200  			fvm.WithAccountKeyWeightThreshold(1000),
   201  			fvm.WithSequenceNumberCheckAndIncrementEnabled(false),
   202  			fvm.WithTransactionBodyExecutionEnabled(false))
   203  		err = run(tx, ctx, txnState)
   204  		require.Error(t, err)
   205  
   206  		// TODO: update to InvalidEnvelopeSignatureError once FVM verifier is updated.
   207  		require.True(t, errors.IsInvalidPayloadSignatureError(err))
   208  	})
   209  }