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  }