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 }