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 }