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 }