github.com/koko1123/flow-go-1@v0.29.6/fvm/transactionVerifier_test.go (about)

     1  package fvm_test
     2  
     3  import (
     4  	"strings"
     5  	"testing"
     6  
     7  	"github.com/stretchr/testify/require"
     8  
     9  	"github.com/koko1123/flow-go-1/fvm"
    10  	"github.com/koko1123/flow-go-1/fvm/crypto"
    11  	"github.com/koko1123/flow-go-1/fvm/environment"
    12  	"github.com/koko1123/flow-go-1/fvm/errors"
    13  	"github.com/koko1123/flow-go-1/fvm/state"
    14  	"github.com/koko1123/flow-go-1/fvm/utils"
    15  	"github.com/koko1123/flow-go-1/model/flow"
    16  	"github.com/koko1123/flow-go-1/utils/unittest"
    17  )
    18  
    19  func TestTransactionVerification(t *testing.T) {
    20  	ledger := utils.NewSimpleView()
    21  	txnState := state.NewTransactionState(ledger, state.DefaultParameters())
    22  	accounts := environment.NewAccounts(txnState)
    23  
    24  	// create 2 accounts
    25  	address1 := flow.HexToAddress("1234")
    26  	privKey1, err := unittest.AccountKeyDefaultFixture()
    27  	require.NoError(t, err)
    28  
    29  	err = accounts.Create([]flow.AccountPublicKey{privKey1.PublicKey(1000)}, address1)
    30  	require.NoError(t, err)
    31  
    32  	address2 := flow.HexToAddress("1235")
    33  	privKey2, err := unittest.AccountKeyDefaultFixture()
    34  	require.NoError(t, err)
    35  
    36  	err = accounts.Create([]flow.AccountPublicKey{privKey2.PublicKey(1000)}, address2)
    37  	require.NoError(t, err)
    38  
    39  	tx := flow.TransactionBody{}
    40  
    41  	t.Run("duplicated authorization signatures", func(t *testing.T) {
    42  
    43  		sig := flow.TransactionSignature{
    44  			Address:     address1,
    45  			SignerIndex: 0,
    46  			KeyIndex:    0,
    47  		}
    48  
    49  		tx.SetProposalKey(address1, 0, 0)
    50  		tx.SetPayer(address1)
    51  
    52  		tx.PayloadSignatures = []flow.TransactionSignature{sig, sig}
    53  		proc := fvm.Transaction(&tx, 0)
    54  
    55  		ctx := fvm.NewContext(
    56  			fvm.WithAuthorizationChecksEnabled(true),
    57  			fvm.WithAccountKeyWeightThreshold(1000),
    58  			fvm.WithSequenceNumberCheckAndIncrementEnabled(false),
    59  			fvm.WithTransactionBodyExecutionEnabled(false))
    60  		err = fvm.Run(proc.NewExecutor(ctx, txnState, nil))
    61  		require.Nil(t, err)
    62  		require.Error(t, proc.Err)
    63  		require.True(t, strings.Contains(proc.Err.Error(), "duplicate signatures are provided for the same key"))
    64  	})
    65  	t.Run("duplicated authorization and envelope signatures", func(t *testing.T) {
    66  
    67  		sig := flow.TransactionSignature{
    68  			Address:     address1,
    69  			SignerIndex: 0,
    70  			KeyIndex:    0,
    71  		}
    72  
    73  		tx.SetProposalKey(address1, 0, 0)
    74  		tx.SetPayer(address1)
    75  
    76  		tx.PayloadSignatures = []flow.TransactionSignature{sig}
    77  		tx.EnvelopeSignatures = []flow.TransactionSignature{sig}
    78  		proc := fvm.Transaction(&tx, 0)
    79  
    80  		ctx := fvm.NewContext(
    81  			fvm.WithAuthorizationChecksEnabled(true),
    82  			fvm.WithAccountKeyWeightThreshold(1000),
    83  			fvm.WithSequenceNumberCheckAndIncrementEnabled(false),
    84  			fvm.WithTransactionBodyExecutionEnabled(false))
    85  		err = fvm.Run(proc.NewExecutor(ctx, txnState, nil))
    86  		require.Nil(t, err)
    87  		require.Error(t, proc.Err)
    88  		require.True(t, strings.Contains(proc.Err.Error(), "duplicate signatures are provided for the same key"))
    89  	})
    90  
    91  	t.Run("invalid envelope signature", func(t *testing.T) {
    92  		tx.SetProposalKey(address1, 0, 0)
    93  		tx.SetPayer(address2)
    94  
    95  		// assign a valid payload signature
    96  		hasher1, err := crypto.NewPrefixedHashing(privKey1.HashAlgo, flow.TransactionTagString)
    97  		require.NoError(t, err)
    98  		validSig, err := privKey1.PrivateKey.Sign(tx.PayloadMessage(), hasher1) // valid signature
    99  		require.NoError(t, err)
   100  
   101  		sig1 := flow.TransactionSignature{
   102  			Address:     address1,
   103  			SignerIndex: 0,
   104  			KeyIndex:    0,
   105  			Signature:   validSig,
   106  		}
   107  
   108  		sig2 := flow.TransactionSignature{
   109  			Address:     address2,
   110  			SignerIndex: 0,
   111  			KeyIndex:    0,
   112  			// invalid signature
   113  		}
   114  
   115  		tx.PayloadSignatures = []flow.TransactionSignature{sig1}
   116  		tx.EnvelopeSignatures = []flow.TransactionSignature{sig2}
   117  
   118  		proc := fvm.Transaction(&tx, 0)
   119  		ctx := fvm.NewContext(
   120  			fvm.WithAuthorizationChecksEnabled(true),
   121  			fvm.WithAccountKeyWeightThreshold(1000),
   122  			fvm.WithSequenceNumberCheckAndIncrementEnabled(false),
   123  			fvm.WithTransactionBodyExecutionEnabled(false))
   124  		err = fvm.Run(proc.NewExecutor(ctx, txnState, nil))
   125  		require.Nil(t, err)
   126  		require.Error(t, proc.Err)
   127  
   128  		require.True(t, errors.IsInvalidEnvelopeSignatureError(proc.Err))
   129  	})
   130  
   131  	t.Run("invalid payload signature", func(t *testing.T) {
   132  		tx.SetProposalKey(address1, 0, 0)
   133  		tx.SetPayer(address2)
   134  
   135  		sig1 := flow.TransactionSignature{
   136  			Address:     address1,
   137  			SignerIndex: 0,
   138  			KeyIndex:    0,
   139  			// invalid signature
   140  		}
   141  
   142  		// assign a valid envelope signature
   143  		hasher2, err := crypto.NewPrefixedHashing(privKey2.HashAlgo, flow.TransactionTagString)
   144  		require.NoError(t, err)
   145  		validSig, err := privKey2.PrivateKey.Sign(tx.EnvelopeMessage(), hasher2) // valid signature
   146  		require.NoError(t, err)
   147  
   148  		sig2 := flow.TransactionSignature{
   149  			Address:     address2,
   150  			SignerIndex: 0,
   151  			KeyIndex:    0,
   152  			Signature:   validSig,
   153  		}
   154  
   155  		tx.PayloadSignatures = []flow.TransactionSignature{sig1}
   156  		tx.EnvelopeSignatures = []flow.TransactionSignature{sig2}
   157  
   158  		proc := fvm.Transaction(&tx, 0)
   159  		ctx := fvm.NewContext(
   160  			fvm.WithAuthorizationChecksEnabled(true),
   161  			fvm.WithAccountKeyWeightThreshold(1000),
   162  			fvm.WithSequenceNumberCheckAndIncrementEnabled(false),
   163  			fvm.WithTransactionBodyExecutionEnabled(false))
   164  		err = fvm.Run(proc.NewExecutor(ctx, txnState, nil))
   165  		require.Nil(t, err)
   166  		require.Error(t, proc.Err)
   167  
   168  		require.True(t, errors.IsInvalidPayloadSignatureError(proc.Err))
   169  	})
   170  
   171  	t.Run("invalid payload and envelope signatures", func(t *testing.T) {
   172  		// TODO: this test expects a Payload error but should be updated to expect en Envelope error.
   173  		// The test should be updated once the FVM updates the order of validating signatures:
   174  		// envelope needs to be checked first and payload later.
   175  		tx.SetProposalKey(address1, 0, 0)
   176  		tx.SetPayer(address2)
   177  
   178  		sig1 := flow.TransactionSignature{
   179  			Address:     address1,
   180  			SignerIndex: 0,
   181  			KeyIndex:    0,
   182  			// invalid signature
   183  		}
   184  
   185  		sig2 := flow.TransactionSignature{
   186  			Address:     address2,
   187  			SignerIndex: 0,
   188  			KeyIndex:    0,
   189  			// invalid signature
   190  		}
   191  
   192  		tx.PayloadSignatures = []flow.TransactionSignature{sig1}
   193  		tx.EnvelopeSignatures = []flow.TransactionSignature{sig2}
   194  
   195  		proc := fvm.Transaction(&tx, 0)
   196  		ctx := fvm.NewContext(
   197  			fvm.WithAuthorizationChecksEnabled(true),
   198  			fvm.WithAccountKeyWeightThreshold(1000),
   199  			fvm.WithSequenceNumberCheckAndIncrementEnabled(false),
   200  			fvm.WithTransactionBodyExecutionEnabled(false))
   201  		err = fvm.Run(proc.NewExecutor(ctx, txnState, nil))
   202  		require.Nil(t, err)
   203  		require.Error(t, proc.Err)
   204  
   205  		// TODO: update to InvalidEnvelopeSignatureError once FVM verifier is updated.
   206  		require.True(t, errors.IsInvalidPayloadSignatureError(proc.Err))
   207  	})
   208  
   209  	t.Run("frozen account is rejected", func(t *testing.T) {
   210  		ctx := fvm.NewContext(
   211  			fvm.WithAuthorizationChecksEnabled(true),
   212  			fvm.WithAccountKeyWeightThreshold(-1),
   213  			fvm.WithSequenceNumberCheckAndIncrementEnabled(false),
   214  			fvm.WithTransactionBodyExecutionEnabled(false))
   215  
   216  		frozenAddress, notFrozenAddress, st := makeTwoAccounts(t, nil, nil)
   217  		accounts := environment.NewAccounts(st)
   218  
   219  		// freeze account
   220  		err := accounts.SetAccountFrozen(frozenAddress, true)
   221  		require.NoError(t, err)
   222  
   223  		// make sure freeze status is correct
   224  		frozen, err := accounts.GetAccountFrozen(frozenAddress)
   225  		require.NoError(t, err)
   226  		require.True(t, frozen)
   227  
   228  		frozen, err = accounts.GetAccountFrozen(notFrozenAddress)
   229  		require.NoError(t, err)
   230  		require.False(t, frozen)
   231  
   232  		// Authorizers
   233  		tx := fvm.Transaction(&flow.TransactionBody{
   234  			Payer:       notFrozenAddress,
   235  			ProposalKey: flow.ProposalKey{Address: notFrozenAddress},
   236  		}, 0)
   237  
   238  		err = fvm.Run(tx.NewExecutor(ctx, st, nil))
   239  		require.NoError(t, err)
   240  		require.NoError(t, tx.Err)
   241  
   242  		tx = fvm.Transaction(&flow.TransactionBody{
   243  			Payer:       notFrozenAddress,
   244  			ProposalKey: flow.ProposalKey{Address: notFrozenAddress},
   245  			Authorizers: []flow.Address{notFrozenAddress},
   246  		}, 0)
   247  		err = fvm.Run(tx.NewExecutor(ctx, st, nil))
   248  		require.NoError(t, err)
   249  		require.NoError(t, tx.Err)
   250  
   251  		tx = fvm.Transaction(&flow.TransactionBody{
   252  			Payer:       notFrozenAddress,
   253  			ProposalKey: flow.ProposalKey{Address: notFrozenAddress},
   254  			Authorizers: []flow.Address{frozenAddress},
   255  		}, 0)
   256  		err = fvm.Run(tx.NewExecutor(ctx, st, nil))
   257  		require.Nil(t, err)
   258  		require.Error(t, tx.Err)
   259  
   260  		// all addresses must not be frozen
   261  		tx = fvm.Transaction(&flow.TransactionBody{
   262  			Payer:       notFrozenAddress,
   263  			ProposalKey: flow.ProposalKey{Address: notFrozenAddress},
   264  			Authorizers: []flow.Address{frozenAddress, notFrozenAddress},
   265  		}, 0)
   266  		err = fvm.Run(tx.NewExecutor(ctx, st, nil))
   267  		require.Nil(t, err)
   268  		require.Error(t, tx.Err)
   269  
   270  		// Payer should be part of authorizers account, but lets check it separately for completeness
   271  
   272  		tx = fvm.Transaction(&flow.TransactionBody{
   273  			Payer:       notFrozenAddress,
   274  			ProposalKey: flow.ProposalKey{Address: notFrozenAddress},
   275  		}, 0)
   276  		err = fvm.Run(tx.NewExecutor(ctx, st, nil))
   277  		require.NoError(t, err)
   278  		require.NoError(t, tx.Err)
   279  
   280  		tx = fvm.Transaction(&flow.TransactionBody{
   281  			Payer:       frozenAddress,
   282  			ProposalKey: flow.ProposalKey{Address: notFrozenAddress},
   283  		}, 0)
   284  		err = fvm.Run(tx.NewExecutor(ctx, st, nil))
   285  		require.Nil(t, err)
   286  		require.Error(t, tx.Err)
   287  
   288  		// Proposal account
   289  
   290  		tx = fvm.Transaction(&flow.TransactionBody{
   291  			Payer:       notFrozenAddress,
   292  			ProposalKey: flow.ProposalKey{Address: frozenAddress},
   293  		}, 0)
   294  		err = fvm.Run(tx.NewExecutor(ctx, st, nil))
   295  		require.Nil(t, err)
   296  		require.Error(t, tx.Err)
   297  
   298  		tx = fvm.Transaction(&flow.TransactionBody{
   299  			Payer:       notFrozenAddress,
   300  			ProposalKey: flow.ProposalKey{Address: notFrozenAddress},
   301  		}, 0)
   302  		err = fvm.Run(tx.NewExecutor(ctx, st, nil))
   303  		require.NoError(t, err)
   304  		require.NoError(t, tx.Err)
   305  	})
   306  }