github.com/kisexp/xdchain@v0.0.0-20211206025815-490d6b732aa7/core/vm/contracts_quorum_test.go (about) 1 package vm 2 3 import ( 4 "crypto/ecdsa" 5 "encoding/json" 6 "errors" 7 "testing" 8 9 "github.com/kisexp/xdchain/common" 10 "github.com/kisexp/xdchain/core/types" 11 "github.com/kisexp/xdchain/crypto" 12 "github.com/kisexp/xdchain/private" 13 "github.com/kisexp/xdchain/private/mock_private" 14 "github.com/golang/mock/gomock" 15 "github.com/stretchr/testify/require" 16 ) 17 18 var ( 19 sender common.Address 20 senderPrivateKey *ecdsa.PrivateKey 21 tmPrivateTxHash common.EncryptedPayloadHash 22 pmtData []byte 23 ) 24 25 func init() { 26 sender = common.HexToAddress("0xed9d02e382b34818e88b88a309c7fe71e65f419d") 27 senderPrivateKey, _ = crypto.HexToECDSA("e6181caaffff94a09d7e332fc8da9884d99902c7874eb74354bdcadf411929f1") 28 29 privateTxHash := crypto.Keccak512([]byte("encrypted-private-tx")) 30 for i := 0; i < 64; i++ { 31 tmPrivateTxHash[i] = privateTxHash[i] 32 } 33 34 pmtData = append(sender.Bytes(), privateTxHash...) 35 } 36 37 func TestPrivacyMarker_Run_UnsupportedTransaction_DoesNothing(t *testing.T) { 38 publicContractCreationTx := types.NewContractCreation(0, nil, 0, nil, []byte{}) 39 privatePrivacyMarkerTx := types.NewTransaction(0, common.QuorumPrivacyPrecompileContractAddress(), nil, 0, nil, []byte{}) 40 privatePrivacyMarkerTx.SetPrivate() 41 require.True(t, privatePrivacyMarkerTx.IsPrivacyMarker()) 42 require.True(t, privatePrivacyMarkerTx.IsPrivate()) 43 44 tests := []struct { 45 name string 46 currentTx *types.Transaction 47 }{ 48 { 49 name: "is-nil", 50 currentTx: nil, 51 }, 52 { 53 name: "is-not-privacy-marker-tx", 54 currentTx: publicContractCreationTx, 55 }, 56 { 57 name: "is-private-privacy-marker-tx", 58 currentTx: privatePrivacyMarkerTx, 59 }, 60 } 61 62 for _, tt := range tests { 63 t.Run(tt.name, func(t *testing.T) { 64 ctrl := gomock.NewController(t) 65 66 pm := privacyMarker{} 67 68 publicState := NewMockStateDB(ctrl) 69 innerApplier := &stubInnerApplier{} 70 71 evm := &EVM{ 72 currentTx: tt.currentTx, 73 publicState: publicState, 74 InnerApply: innerApplier.InnerApply, 75 } 76 77 publicState.EXPECT().SetNonce(gomock.Any(), gomock.Any()).Times(0) 78 79 gotByt, gotErr := pm.Run(evm, []byte{}) 80 81 require.False(t, innerApplier.wasCalled()) 82 require.Nil(t, gotByt) 83 require.Nil(t, gotErr) 84 85 ctrl.Finish() 86 }) 87 } 88 } 89 90 func TestPrivacyMarker_Run_NonZeroEVMDepth_DoesNothing(t *testing.T) { 91 ctrl := gomock.NewController(t) 92 defer ctrl.Finish() 93 94 privacyMarkerTx := types.NewTransaction(0, common.QuorumPrivacyPrecompileContractAddress(), nil, 0, nil, []byte{}) 95 require.True(t, privacyMarkerTx.IsPrivacyMarker()) 96 97 pm := privacyMarker{} 98 99 publicState := NewMockStateDB(ctrl) 100 innerApplier := &stubInnerApplier{} 101 102 depth := 1 103 104 evm := &EVM{ 105 depth: depth, 106 currentTx: privacyMarkerTx, 107 publicState: publicState, 108 InnerApply: innerApplier.InnerApply, 109 } 110 111 publicState.EXPECT().SetNonce(gomock.Any(), gomock.Any()).Times(0) 112 113 gotByt, gotErr := pm.Run(evm, []byte{}) 114 115 require.False(t, innerApplier.wasCalled()) 116 require.Nil(t, gotByt) 117 require.Nil(t, gotErr) 118 } 119 120 func TestPrivacyMarker_Run_InvalidTransaction_NonceUnchanged(t *testing.T) { 121 var ( 122 publicTx *types.Transaction 123 publicTxByt []byte 124 unsignedPrivateTx *types.Transaction 125 incorrectlySignedPrivateTx *types.Transaction 126 incorrectlySignedPrivateTxByt []byte 127 setupErr error 128 ) 129 130 publicTx = types.NewTransaction(0, common.QuorumPrivacyPrecompileContractAddress(), nil, 0, nil, []byte{}) 131 require.False(t, publicTx.IsPrivate()) 132 publicTxByt, setupErr = json.Marshal(publicTx) 133 if setupErr != nil { 134 t.Fatalf("unable to marshal tx to json, err = %v", setupErr) 135 } 136 137 unsignedPrivateTx = types.NewTransaction(0, common.QuorumPrivacyPrecompileContractAddress(), nil, 0, nil, []byte{}) 138 unsignedPrivateTx.SetPrivate() 139 140 invalidSig := common.Hex2Bytes("9bea4c4daac7c7c52e093e6a4c35dbbcf8856f1af7b059ba20253e70848d094f8a8fae537ce25ed8cb5af9adac3f141af69bd515bd2ba031522df09b97dd72b100") 141 incorrectlySignedPrivateTx, setupErr = unsignedPrivateTx.WithSignature( 142 types.QuorumPrivateTxSigner{}, 143 invalidSig, 144 ) 145 if setupErr != nil { 146 t.Fatalf("unable to sign tx, err = %v", setupErr) 147 } 148 require.True(t, incorrectlySignedPrivateTx.IsPrivate()) 149 incorrectlySignedPrivateTxByt, setupErr = json.Marshal(incorrectlySignedPrivateTx) 150 if setupErr != nil { 151 t.Fatalf("unable to marshal tx to json, err = %v", setupErr) 152 } 153 154 tests := []struct { 155 name string 156 privacyManagerResp []byte // decrypted data from privacy manager 157 privacyManagerErr error 158 }{ 159 { 160 name: "privacy-manager-error", 161 privacyManagerResp: nil, 162 privacyManagerErr: errors.New("some error like node is down"), 163 }, 164 { 165 name: "non-participant", 166 privacyManagerResp: nil, 167 privacyManagerErr: nil, 168 }, 169 { 170 name: "internal-tx-is-not-private", 171 privacyManagerResp: publicTxByt, 172 privacyManagerErr: nil, 173 }, 174 { 175 name: "internal-private-tx-has-invalid-signature", 176 privacyManagerResp: incorrectlySignedPrivateTxByt, 177 privacyManagerErr: nil, 178 }, 179 } 180 181 for _, tt := range tests { 182 t.Run(tt.name, func(t *testing.T) { 183 ctrl := gomock.NewController(t) 184 185 unsignedPrivacyMarkerTx := types.NewTransaction(0, common.QuorumPrivacyPrecompileContractAddress(), nil, 0, nil, pmtData) 186 signer := types.HomesteadSigner{} 187 txHash := signer.Hash(unsignedPrivacyMarkerTx) 188 validSig, setupErr := crypto.Sign(txHash.Bytes(), senderPrivateKey) 189 if setupErr != nil { 190 t.Fatalf("unable to sign tx, err = %v", setupErr) 191 } 192 privacyMarkerTx, setupErr := unsignedPrivacyMarkerTx.WithSignature( 193 signer, 194 validSig, 195 ) 196 if setupErr != nil { 197 t.Fatalf("unable to sign tx, err = %v", setupErr) 198 } 199 200 require.True(t, privacyMarkerTx.IsPrivacyMarker()) 201 202 pm := privacyMarker{} 203 204 privacyManager := mock_private.NewMockPrivateTransactionManager(ctrl) 205 private.P = privacyManager 206 publicState := NewMockStateDB(ctrl) 207 innerApplier := nonceIncrementingInnerApplier{ 208 incrementNonceFunc: func() { 209 // this should not be called 210 publicState.SetNonce(sender, 1) 211 }, 212 } 213 214 evm := &EVM{ 215 currentTx: privacyMarkerTx, 216 publicState: publicState, 217 InnerApply: innerApplier.InnerApply, 218 } 219 220 privacyManager.EXPECT().Receive(tmPrivateTxHash).Return("", []string{}, tt.privacyManagerResp, nil, tt.privacyManagerErr) 221 222 publicState.EXPECT().GetNonce(gomock.Any()).Times(0) 223 publicState.EXPECT().SetNonce(gomock.Any(), gomock.Any()).Times(0) 224 225 gotByt, gotErr := pm.Run(evm, []byte{}) 226 227 require.False(t, innerApplier.wasCalled()) 228 require.Nil(t, gotByt) 229 require.Nil(t, gotErr) 230 231 defer ctrl.Finish() 232 }) 233 } 234 } 235 236 func TestPrivacyMarker_Run_SupportedTransaction_ExecutionFails_NonceUnchanged(t *testing.T) { 237 var ( 238 unsignedPrivateTx *types.Transaction 239 signedPrivateTx *types.Transaction 240 signedPrivateTxByt []byte 241 setupErr error 242 ) 243 244 unsignedPrivateTx = types.NewTransaction(0, common.QuorumPrivacyPrecompileContractAddress(), nil, 0, nil, []byte{}) 245 unsignedPrivateTx.SetPrivate() 246 247 signer := types.QuorumPrivateTxSigner{} 248 txHash := signer.Hash(unsignedPrivateTx) 249 250 validSig, setupErr := crypto.Sign(txHash.Bytes(), senderPrivateKey) 251 if setupErr != nil { 252 t.Fatalf("unable to sign tx, err = %v", setupErr) 253 } 254 255 signedPrivateTx, setupErr = unsignedPrivateTx.WithSignature( 256 types.QuorumPrivateTxSigner{}, 257 validSig, 258 ) 259 if setupErr != nil { 260 t.Fatalf("unable to sign tx, err = %v", setupErr) 261 } 262 require.True(t, signedPrivateTx.IsPrivate()) 263 signedPrivateTxByt, setupErr = json.Marshal(signedPrivateTx) 264 if setupErr != nil { 265 t.Fatalf("unable to marshal tx to json, err = %v", setupErr) 266 } 267 268 tests := []struct { 269 name string 270 innerApplier innerApplier 271 }{ 272 { 273 name: "internal-private-tx-execution-fails", 274 innerApplier: &failingInnerApplier{}, 275 }, 276 { 277 name: "internal-private-tx-execution-does-not-increment-nonce", 278 innerApplier: &stubInnerApplier{}, 279 }, 280 } 281 282 for _, tt := range tests { 283 t.Run(tt.name, func(t *testing.T) { 284 ctrl := gomock.NewController(t) 285 286 unsignedPrivacyMarkerTx := types.NewTransaction(0, common.QuorumPrivacyPrecompileContractAddress(), nil, 0, nil, pmtData) 287 signer := types.HomesteadSigner{} 288 txHash := signer.Hash(unsignedPrivacyMarkerTx) 289 validSig, setupErr := crypto.Sign(txHash.Bytes(), senderPrivateKey) 290 if setupErr != nil { 291 t.Fatalf("unable to sign tx, err = %v", setupErr) 292 } 293 privacyMarkerTx, setupErr := unsignedPrivacyMarkerTx.WithSignature( 294 signer, 295 validSig, 296 ) 297 if setupErr != nil { 298 t.Fatalf("unable to sign tx, err = %v", setupErr) 299 } 300 301 require.True(t, privacyMarkerTx.IsPrivacyMarker()) 302 303 pm := privacyMarker{} 304 305 privacyManager := mock_private.NewMockPrivateTransactionManager(ctrl) 306 private.P = privacyManager 307 publicState := NewMockStateDB(ctrl) 308 309 evm := &EVM{ 310 currentTx: privacyMarkerTx, 311 publicState: publicState, 312 InnerApply: tt.innerApplier.InnerApply, 313 } 314 315 var ( 316 senderCurrentNonce uint64 = 10 317 senderPreviousNonce uint64 = 9 318 ) 319 320 privacyManager.EXPECT().Receive(tmPrivateTxHash).Return("", []string{}, signedPrivateTxByt, nil, nil) 321 322 gomock.InOrder( 323 publicState.EXPECT().GetNonce(sender).Return(senderCurrentNonce).Times(1), // getting startingNonce 324 publicState.EXPECT().SetNonce(sender, senderPreviousNonce).Times(1), // decrementing nonce to prepare for pvt tx execution 325 publicState.EXPECT().SetNonce(sender, senderCurrentNonce).Times(1), // resetting nonce to startingNonce 326 ) 327 328 gotByt, gotErr := pm.Run(evm, []byte{}) 329 330 require.True(t, tt.innerApplier.wasCalled()) 331 require.Nil(t, gotByt) 332 require.Nil(t, gotErr) 333 334 executedTx := tt.innerApplier.innerTx() 335 336 // we only want to compare the values that matter in the embedded txdata - this is unexported so we resort to 337 // using the string representation of the txs for comparison 338 require.EqualValues(t, signedPrivateTx.String(), executedTx.String()) 339 340 defer ctrl.Finish() 341 }) 342 } 343 } 344 345 func TestPrivacyMarker_Run_SupportedTransaction_ExecutionSucceeds_NonceUnchanged(t *testing.T) { 346 ctrl := gomock.NewController(t) 347 defer ctrl.Finish() 348 349 var ( 350 unsignedPrivateTx *types.Transaction 351 signedPrivateTx *types.Transaction 352 signedPrivateTxByt []byte 353 setupErr error 354 ) 355 356 unsignedPrivateTx = types.NewTransaction(0, common.QuorumPrivacyPrecompileContractAddress(), nil, 0, nil, []byte{}) 357 unsignedPrivateTx.SetPrivate() 358 359 signer := types.QuorumPrivateTxSigner{} 360 txHash := signer.Hash(unsignedPrivateTx) 361 362 validSig, setupErr := crypto.Sign(txHash.Bytes(), senderPrivateKey) 363 if setupErr != nil { 364 t.Fatalf("unable to sign tx, err = %v", setupErr) 365 } 366 367 signedPrivateTx, setupErr = unsignedPrivateTx.WithSignature( 368 types.QuorumPrivateTxSigner{}, 369 validSig, 370 ) 371 if setupErr != nil { 372 t.Fatalf("unable to sign tx, err = %v", setupErr) 373 } 374 require.True(t, signedPrivateTx.IsPrivate()) 375 signedPrivateTxByt, setupErr = json.Marshal(signedPrivateTx) 376 if setupErr != nil { 377 t.Fatalf("unable to marshal tx to json, err = %v", setupErr) 378 } 379 380 unsignedPrivacyMarkerTx := types.NewTransaction(0, common.QuorumPrivacyPrecompileContractAddress(), nil, 0, nil, pmtData) 381 ptmSigner := types.HomesteadSigner{} 382 ptmHash := ptmSigner.Hash(unsignedPrivacyMarkerTx) 383 validSig, setupErr = crypto.Sign(ptmHash.Bytes(), senderPrivateKey) 384 if setupErr != nil { 385 t.Fatalf("unable to sign tx, err = %v", setupErr) 386 } 387 privacyMarkerTx, setupErr := unsignedPrivacyMarkerTx.WithSignature( 388 ptmSigner, 389 validSig, 390 ) 391 if setupErr != nil { 392 t.Fatalf("unable to sign tx, err = %v", setupErr) 393 } 394 395 require.True(t, privacyMarkerTx.IsPrivacyMarker()) 396 397 pm := privacyMarker{} 398 399 privacyManager := mock_private.NewMockPrivateTransactionManager(ctrl) 400 private.P = privacyManager 401 publicState := NewMockStateDB(ctrl) 402 403 var ( 404 senderCurrentNonce uint64 = 10 405 senderPreviousNonce uint64 = 9 406 ) 407 408 innerApplier := nonceIncrementingInnerApplier{ 409 incrementNonceFunc: func() { 410 publicState.SetNonce(sender, senderPreviousNonce+1) 411 }, 412 } 413 414 evm := &EVM{ 415 currentTx: privacyMarkerTx, 416 publicState: publicState, 417 InnerApply: innerApplier.InnerApply, 418 } 419 420 privacyManager.EXPECT().Receive(tmPrivateTxHash).Return("", []string{}, signedPrivateTxByt, nil, nil) 421 422 gomock.InOrder( 423 publicState.EXPECT().GetNonce(sender).Return(senderCurrentNonce).Times(1), // getting startingNonce 424 publicState.EXPECT().SetNonce(sender, senderPreviousNonce).Times(1), // decrementing nonce to prepare for pvt tx execution 425 publicState.EXPECT().SetNonce(sender, senderCurrentNonce).Times(1), // the call in nonceIncrementingInnerApplier 426 publicState.EXPECT().SetNonce(sender, senderCurrentNonce).Times(1), // resetting nonce to startingNonce 427 ) 428 429 gotByt, gotErr := pm.Run(evm, []byte{}) 430 431 require.True(t, innerApplier.wasCalled()) 432 require.Nil(t, gotByt) 433 require.Nil(t, gotErr) 434 435 executedTx := innerApplier.innerTx() 436 437 // we only want to compare the values the matter in the embedded txdata - this is unexported so we resort to 438 // using the string representation of the txs for comparison 439 require.EqualValues(t, signedPrivateTx.String(), executedTx.String()) 440 } 441 442 type innerApplier interface { 443 InnerApply(innerTx *types.Transaction) error 444 wasCalled() bool 445 innerTx() *types.Transaction 446 } 447 448 type stubInnerApplier struct { 449 called bool 450 tx *types.Transaction 451 } 452 453 func (m *stubInnerApplier) InnerApply(innerTx *types.Transaction) error { 454 m.called = true 455 m.tx = innerTx 456 return nil 457 } 458 459 func (m *stubInnerApplier) wasCalled() bool { 460 return m.called 461 } 462 463 func (m *stubInnerApplier) innerTx() *types.Transaction { 464 return m.tx 465 } 466 467 type failingInnerApplier struct { 468 called bool 469 tx *types.Transaction 470 } 471 472 func (m *failingInnerApplier) InnerApply(innerTx *types.Transaction) error { 473 m.called = true 474 m.tx = innerTx 475 return errors.New("some error") 476 } 477 478 func (m *failingInnerApplier) wasCalled() bool { 479 return m.called 480 } 481 482 func (m *failingInnerApplier) innerTx() *types.Transaction { 483 return m.tx 484 } 485 486 type nonceIncrementingInnerApplier struct { 487 called bool 488 tx *types.Transaction 489 incrementNonceFunc func() 490 } 491 492 func (m *nonceIncrementingInnerApplier) InnerApply(innerTx *types.Transaction) error { 493 m.called = true 494 m.tx = innerTx 495 496 m.incrementNonceFunc() 497 498 return nil 499 } 500 501 func (m *nonceIncrementingInnerApplier) wasCalled() bool { 502 return m.called 503 } 504 505 func (m *nonceIncrementingInnerApplier) innerTx() *types.Transaction { 506 return m.tx 507 }