github.com/coltonfike/e2c@v21.1.0+incompatible/core/types/transaction_signing_quorum_test.go (about)

     1  // Copyright 2014 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package types
    18  
    19  import (
    20  	"crypto/ecdsa"
    21  	"crypto/elliptic"
    22  	"fmt"
    23  	"math/big"
    24  	"testing"
    25  
    26  	"github.com/ethereum/go-ethereum/common"
    27  	"github.com/ethereum/go-ethereum/crypto"
    28  	testifyassert "github.com/stretchr/testify/assert"
    29  )
    30  
    31  // run all the tests in this file
    32  // $> go test $(go list ./...) -run TestSignQuorum
    33  
    34  // private key material to test both 0 and 1 bit for the recoveryId (v).
    35  // key with v sign == 28 (Homestead)
    36  var k0v, _ = new(big.Int).SetString("25807260602402504536675820444142779248993100028628438487502323668296269534891", 10)
    37  
    38  // key with v sign == 27 (Homestead)
    39  var k1v, _ = new(big.Int).SetString("10148397294747000913768625849546502595195728826990639993137198410557736548965", 10)
    40  
    41  // helper to deterministically create an ECDSA key from an int.
    42  func createKey(c elliptic.Curve, k *big.Int) (*ecdsa.PrivateKey, error) {
    43  	sk := new(ecdsa.PrivateKey)
    44  	sk.PublicKey.Curve = c
    45  	sk.D = k
    46  	sk.PublicKey.X, sk.PublicKey.Y = c.ScalarBaseMult(k.Bytes())
    47  	return sk, nil
    48  }
    49  
    50  func signTx(key *ecdsa.PrivateKey, signer Signer) (*Transaction, common.Address, error) {
    51  	addr := crypto.PubkeyToAddress(key.PublicKey)
    52  	tx := NewTransaction(0, addr, new(big.Int), 0, new(big.Int), nil)
    53  	signedTx, err := SignTx(tx, signer, key)
    54  	//fmt.Printf("\ntx.data.V signTx after sign [%v] \n", signedTx.data.V)
    55  	return signedTx, addr, err
    56  }
    57  
    58  /**
    59   * As of quorum v2.2.3 commit be7cc31ce208525ea1822e7d0fee88bf7f14500b 30 April 2019 behavior
    60   *
    61   * Test public transactions signed by homestead Signer. Homestead sets the v param on a signed transaction to
    62   * either 27 or 28. The v parameter is used for recovering the sender of the signed transaction.
    63   *
    64   *  1. Homestead: should be 27, 28
    65   * $> go test -run TestSignQuorumHomesteadPublic
    66   */
    67  func TestSignQuorumHomesteadPublic(t *testing.T) {
    68  
    69  	assert := testifyassert.New(t)
    70  
    71  	k0, _ := createKey(crypto.S256(), k0v)
    72  	k1, _ := createKey(crypto.S256(), k1v)
    73  
    74  	homeSinger := HomesteadSigner{}
    75  
    76  	// odd parity should be 27 for Homestead
    77  	signedTx, addr, _ := signTx(k1, homeSinger)
    78  
    79  	assert.True(signedTx.data.V.Cmp(big.NewInt(27)) == 0, fmt.Sprintf("v wasn't 27 it was [%v]", signedTx.data.V))
    80  
    81  	// recover address from signed TX
    82  	from, _ := Sender(homeSinger, signedTx)
    83  	//fmt.Printf("from [%v] == addr [%v]\n\n", from, from == addr)
    84  	assert.True(from == addr, fmt.Sprintf("Expected from and address to be equal. Got %x want %x", from, addr))
    85  
    86  	// even parity should be 28 for Homestead
    87  	signedTx, addr, _ = signTx(k0, homeSinger)
    88  	assert.True(signedTx.data.V.Cmp(big.NewInt(28)) == 0, fmt.Sprintf("v wasn't 28 it was [%v]\n", signedTx.data.V))
    89  
    90  	// recover address from signed TX
    91  	from, _ = Sender(homeSinger, signedTx)
    92  	//fmt.Printf("from [%v] == addr [%v]\n", from, from == addr)
    93  	assert.True(from == addr, fmt.Sprintf("Expected from and address to be equal. Got %x want %x", from, addr))
    94  
    95  }
    96  
    97  /**
    98   * As of quorum v2.2.3 commit be7cc31ce208525ea1822e7d0fee88bf7f14500b 30 April 2019 behavior
    99   *
   100   * Test the public transactions signed by the EIP155Signer.
   101   * The EIP155Signer was introduced to protect against replay
   102   * attacks https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md and stores
   103   * the CHAINID in the signed transaction's `v` parameter as `v = chainId * 2 + 35`.
   104   *
   105   * The EthEIP155Signer change breaks private quorum transactions when the chainId == 1 (mainnet chainId),
   106   * as the v parameter on a public transaction and on a private transaction will both be 37, 38.
   107   *
   108   *  $> go test -run TestSignQuorumEIP155Public
   109   */
   110  func TestSignQuorumEIP155Public(t *testing.T) {
   111  
   112  	assert := testifyassert.New(t)
   113  
   114  	k0, _ := createKey(crypto.S256(), k0v)
   115  	k1, _ := createKey(crypto.S256(), k1v)
   116  
   117  	// chainId 1 even EIP155Signer should be 37 conflicts with private transaction
   118  	var chainId int64 = 2 // 7 2 10
   119  
   120  	v0 := chainId*2 + 35 // sig[64] + 35 .. where sig[64] == 0
   121  	v1 := chainId*2 + 36 // sig[64] + 35 .. where sig[64] == 1
   122  
   123  	// Will calculate v to be `v = CHAINID * 2 + 35`
   124  	// To compute V:
   125  	// 	2 * 2 + 35 == 39
   126  	// 	2 * 2 + 36 == 40
   127  	// To retrieve Sender, pull out 27, 28 Eth Frontier / Homestead values.
   128  	// 	39 - (2 * 2) - 8 == 27
   129  	// 	40 - (2 * 2) - 8 == 28
   130  	EIPsigner := NewEIP155Signer(big.NewInt(chainId))
   131  
   132  	signedTx, addr, _ := signTx(k0, EIPsigner)
   133  
   134  	//fmt.Printf("After signing V is [%v] \n", signedTx.data.V)
   135  	assert.True(signedTx.data.V.Cmp(big.NewInt(v0)) == 0, fmt.Sprintf("v wasn't [%v] it was [%v]\n", v0, signedTx.data.V))
   136  	from, _ := Sender(EIPsigner, signedTx)
   137  
   138  	assert.True(from == addr, fmt.Sprintf("Expected from and address to be equal. Got %x want %x", from, addr))
   139  
   140  	// chainId 1 even  EIP155Signer should be 38 conflicts with private transaction
   141  	assert.False(signedTx.IsPrivate(), fmt.Sprintf("Public transaction is set to a private transition v == [%v]", signedTx.data.V))
   142  
   143  	signedTx, addr, _ = signTx(k1, EIPsigner)
   144  
   145  	assert.True(signedTx.data.V.Cmp(big.NewInt(v1)) == 0, fmt.Sprintf("v wasn't [%v], it was [%v]\n", v1, signedTx.data.V))
   146  	from, _ = Sender(EIPsigner, signedTx)
   147  
   148  	assert.True(from == addr, fmt.Sprintf("Expected from and address to be equal. Got %x want %x", from, addr))
   149  
   150  }
   151  
   152  /**
   153   *  As of quorum v2.2.3 commit be7cc31ce208525ea1822e7d0fee88bf7f14500b 30 April 2019 behavior
   154   *
   155   * When the signer is EIP155Signer, chainId == 1 cannot be used because the EIP155 computed `v` value conflicts
   156   * with the private `v` value that quorum uses to indicate a private transaction: v == 37 and v == 38.
   157   *
   158   *  $> go test -run TestSignQuorumEIP155FailPublicChain1
   159   */
   160  func TestSignQuorumEIP155FailPublicChain1(t *testing.T) {
   161  
   162  	assert := testifyassert.New(t)
   163  
   164  	k0, _ := createKey(crypto.S256(), k0v)
   165  	k1, _ := createKey(crypto.S256(), k1v)
   166  
   167  	// chainId 1 even  EIP155Signer should be 37.38 which conflicts with private transaction
   168  	var chainId int64 = 1
   169  
   170  	v0 := chainId*2 + 35 // sig[64] + 35 .. where sig[64] == 0
   171  	v1 := chainId*2 + 36 // sig[64] + 35 .. where sig[64] == 1
   172  
   173  	// Will calculate v to be `v = CHAINID * 2 + 35`
   174  	// To compute V:
   175  	// 	2 * 1 + 35 == 37
   176  	// 	2 * 1 + 36 == 38
   177  	// To retrieve Sender, pull out 27, 28 Eth Frontier / Homestead values.
   178  	// 	37 - (1 * 2) - 8 == 27
   179  	// 	38 - (1 * 2) - 8 == 28
   180  	EIPsigner := NewEIP155Signer(big.NewInt(chainId))
   181  
   182  	signedTx, addr, _ := signTx(k0, EIPsigner)
   183  
   184  	// the calculated v value should equal `chainId * 2 + 35 `
   185  	assert.True(signedTx.data.V.Cmp(big.NewInt(v0)) == 0, fmt.Sprintf("v wasn't [%v] it was "+
   186  		"[%v]\n", v0, signedTx.data.V))
   187  	// the sender will not be equal as HomesteadSigner{}.Sender(tx) is used because IsPrivate() will be true
   188  	// although it is a public tx.
   189  	// This is test to catch when / if this behavior changes.
   190  	assert.True(signedTx.IsPrivate(), "A public transaction with EIP155 and chainID 1 is expected to be "+
   191  		"considered private, as its v param conflict with a private transaction. signedTx.IsPrivate() == [%v]", signedTx.IsPrivate())
   192  	from, _ := Sender(EIPsigner, signedTx)
   193  
   194  	assert.False(from == addr, fmt.Sprintf("Expected the sender of a public TX from chainId 1, \n "+
   195  		"should not be recoverable from [%x] addr [%v] ", from, addr))
   196  
   197  	signedTx, addr, _ = signTx(k1, EIPsigner)
   198  
   199  	// the calculated v value should equal `chainId * 2 + 35`
   200  	assert.True(signedTx.data.V.Cmp(big.NewInt(v1)) == 0,
   201  		fmt.Sprintf("v wasn't [%v] it was [%v]", v1, signedTx.data.V))
   202  
   203  	// the sender will not be equal as HomesteadSigner{}.Sender(tx) is used because IsPrivate() will be true
   204  	// although it is a public tx.
   205  	// This is test to catch when / if this behavior changes.
   206  	// we are signing the data with EIPsigner and chainID 1, so this would be considered a private tx.
   207  	assert.True(signedTx.IsPrivate(), "A public transaction with EIP155 and chainID 1 is expected to "+
   208  		"to be considered private, as its v param conflict with a private transaction. "+
   209  		"signedTx.IsPrivate() == [%v]", signedTx.IsPrivate())
   210  	from, _ = Sender(EIPsigner, signedTx)
   211  
   212  	assert.False(from == addr, fmt.Sprintf("Expected the sender of a public TX from chainId 1, "+
   213  		"should not be recoverable from [%x] addr [%v] ", from, addr))
   214  
   215  }
   216  
   217  /**
   218  *  As of quorum v2.2.3 commit be7cc31ce208525ea1822e7d0fee88bf7f14500b 30 April 2019 behavior
   219  *
   220  *  Use Homestead to sign and EIPSigner to recover.
   221  *
   222  *  SendTransaction creates a transaction for the given argument, signs it and submit it to the transaction pool.
   223  *  func (s *PublicTransactionPoolAPI) SendTransaction(ctx context.Context, args SendTxArgs) (common.Hash, error) {
   224  *  Current implementation in `internal/ethapi/api.go`
   225  *
   226  *  accounts/keystore/keystore.SignTx(): would hash and sign with homestead
   227  *
   228  *  When a private tx (obtained from json params PrivateFor) is submitted `internal/ethapi/api.go`:
   229  *
   230  *  1. sign with HomesteadSigner, this will set the v parameter to
   231  *     27 or 28. // there is no indication that this is a private tx yet.
   232  *
   233  *  2. when submitting a transaction `submitTransaction(ctx context.Context, b Backend, tx *types.Transaction, isPrivate bool)`
   234        check isPrivate param, and call `tx.SetPrivate()`, this will update the `v` signature param (recoveryID)
   235  *     from 27 -> 37, 28 -> 38. // this is now considered a private tx.
   236  *
   237  *  $> go test -run TestSignQuorumHomesteadEIP155SigningPrivateQuorum
   238  */
   239  func TestSignQuorumHomesteadEIP155SigningPrivateQuorum(t *testing.T) {
   240  
   241  	assert := testifyassert.New(t)
   242  
   243  	keys := []*big.Int{k0v, k1v}
   244  
   245  	homeSinger := HomesteadSigner{}
   246  	recoverySigner := NewEIP155Signer(big.NewInt(18))
   247  
   248  	// check for both sig[64] == 0, and sig[64] == 1
   249  	for i := 0; i < len(keys); i++ {
   250  		key, _ := createKey(crypto.S256(), keys[i])
   251  		signedTx, addr, err := signTx(key, homeSinger)
   252  
   253  		assert.Nil(err, err)
   254  		// set to privateTX after the initial signing, this explicitly sets the v param.
   255  		// Note: only works when the tx was signed with the homesteadSinger (v==27 | 28).
   256  		signedTx.SetPrivate()
   257  
   258  		assert.True(signedTx.IsPrivate(), fmt.Sprintf("Expected the transaction to be private [%v]", signedTx.IsPrivate()))
   259  		// Try to recover Sender
   260  		from, err := Sender(recoverySigner, signedTx)
   261  
   262  		assert.Nil(err, err)
   263  		assert.True(from == addr, fmt.Sprintf("Expected from and address to be equal. Got %x want %x", from, addr))
   264  	}
   265  
   266  }
   267  
   268  /*
   269   * As of quorum v2.2.3 commit be7cc31ce208525ea1822e7d0fee88bf7f14500b 30 April 2019 behavior
   270   * Use Homestead to sign and Homestead to recover.
   271   *
   272   * Signing private transactions with HomesteadSigner, and recovering a private transaction with
   273   * HomesteadSigner works, but the transaction has to be set to private `signedTx.SetPrivate()` after
   274   * the signature and before recovering the address.
   275   *
   276   *  $> go test -run TestSignQuorumHomesteadOnlyPrivateQuorum
   277   */
   278  func TestSignQuorumHomesteadOnlyPrivateQuorum(t *testing.T) {
   279  
   280  	assert := testifyassert.New(t)
   281  
   282  	// check even and odd parity
   283  	keys := []*big.Int{k0v, k1v}
   284  
   285  	homeSinger := HomesteadSigner{}
   286  	recoverySigner := HomesteadSigner{}
   287  
   288  	for i := 0; i < len(keys); i++ {
   289  		key, _ := createKey(crypto.S256(), keys[i])
   290  		signedTx, addr, err := signTx(key, homeSinger)
   291  
   292  		assert.Nil(err, err)
   293  
   294  		//fmt.Printf("Private tx.data.V Home [%v] \n", signedTx.data.V)
   295  		// set to privateTX after the initial signing.
   296  		signedTx.SetPrivate()
   297  		assert.True(signedTx.IsPrivate(), fmt.Sprintf("Expected the transaction to be "+
   298  			"private [%v]", signedTx.IsPrivate()))
   299  		//fmt.Printf("Private tx.data.V Home [%v] \n", signedTx.data.V)
   300  
   301  		// Try to recover Sender
   302  		from, err := Sender(recoverySigner, signedTx)
   303  
   304  		assert.Nil(err, err)
   305  		assert.True(from == addr, fmt.Sprintf("Expected from and address to be equal. "+
   306  			" Got %x want %x", from, addr))
   307  	}
   308  
   309  }
   310  
   311  /*
   312   * As of quorum v2.2.3 commit be7cc31ce208525ea1822e7d0fee88bf7f14500b 30 April 2019 behavior
   313   *
   314   * Use EIP155 to sign and EIP155 to recover (This is not a valid combination and does **not** work).
   315   *
   316   * Signing private transactions with EIP155Signer, and recovering a private transaction with
   317   * EIP155Signer does **not** work.
   318   * note: deriveChainId only checks for 27, 28 when using EIP155
   319   * note: In the case where the v param is not 27 or 28 when setting private it will always be set to 37
   320   *
   321   *  $> go test -run TestSignQuorumEIP155OnlyPrivateQuorum
   322   */
   323  func TestSignQuorumEIP155OnlyPrivateQuorum(t *testing.T) {
   324  
   325  	assert := testifyassert.New(t)
   326  
   327  	// check even and odd parity
   328  	keys := []*big.Int{k0v, k1v}
   329  
   330  	EIP155Signer := NewEIP155Signer(big.NewInt(0))
   331  
   332  	for i := 0; i < len(keys); i++ {
   333  		key, _ := createKey(crypto.S256(), keys[i])
   334  		signedTx, addr, err := signTx(key, EIP155Signer)
   335  
   336  		assert.Nil(err, err)
   337  		//fmt.Printf("Private tx.data.V Home [%v] \n", signedTx.data.V)
   338  
   339  		// set to privateTX after the initial signing.
   340  		signedTx.SetPrivate()
   341  
   342  		assert.True(signedTx.IsPrivate(), fmt.Sprintf("Expected the transaction to be private [%v]", signedTx.IsPrivate()))
   343  		//fmt.Printf("Private tx.data.V Home [%v] \n", signedTx.data.V)
   344  
   345  		// Try to recover Sender
   346  		from, err := Sender(EIP155Signer, signedTx)
   347  
   348  		assert.Nil(err, err)
   349  		assert.False(from == addr, fmt.Sprintf("Expected recovery to fail. from [%x] should not equal "+
   350  			"addr [%x]", from, addr))
   351  
   352  	}
   353  
   354  }