github.com/klaytn/klaytn@v1.12.1/tests/validate_sender_test.go (about) 1 // Copyright 2019 The klaytn Authors 2 // This file is part of the klaytn library. 3 // 4 // The klaytn 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 klaytn 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 klaytn library. If not, see <http://www.gnu.org/licenses/>. 16 17 package tests 18 19 import ( 20 "crypto/ecdsa" 21 "fmt" 22 "math/big" 23 "strings" 24 "testing" 25 "time" 26 27 "github.com/klaytn/klaytn/accounts/abi" 28 "github.com/klaytn/klaytn/blockchain/types" 29 "github.com/klaytn/klaytn/common" 30 "github.com/klaytn/klaytn/common/profile" 31 "github.com/klaytn/klaytn/crypto" 32 "github.com/klaytn/klaytn/log" 33 "github.com/klaytn/klaytn/params" 34 "github.com/stretchr/testify/assert" 35 ) 36 37 // TestValidateSenderContract tests a precompiled contract "ValidateSender" whose address is 0xb. 38 // This contract validates the signature that is signed by the sender with the msgHash. 39 func TestValidateSenderContract(t *testing.T) { 40 log.EnableLogForTest(log.LvlCrit, log.LvlTrace) 41 prof := profile.NewProfiler() 42 43 if isCompilerAvailable() == false { 44 if testing.Verbose() { 45 fmt.Printf("TestFeePayerContract is skipped due to the lack of solc.") 46 } 47 return 48 } 49 50 // Initialize blockchain 51 start := time.Now() 52 bcdata, err := NewBCData(6, 4) 53 if err != nil { 54 t.Fatal(err) 55 } 56 prof.Profile("main_init_blockchain", time.Now().Sub(start)) 57 defer bcdata.Shutdown() 58 59 // Initialize address-balance map for verification 60 start = time.Now() 61 accountMap := NewAccountMap() 62 if err := accountMap.Initialize(bcdata); err != nil { 63 t.Fatal(err) 64 } 65 prof.Profile("main_init_accountMap", time.Now().Sub(start)) 66 67 // reservoir account 68 reservoir := &TestAccountType{ 69 Addr: *bcdata.addrs[0], 70 Keys: []*ecdsa.PrivateKey{bcdata.privKeys[0]}, 71 Nonce: uint64(0), 72 } 73 74 // multisigInitial has a initial key pair of multisig before the account key update 75 multisigInitial, err := createAnonymousAccount("aa113e82881499a7a361e8354a5b68f6c6885c7bcba09ea2b0891480396c322e") 76 assert.Equal(t, nil, err) 77 78 // multisig2Initial has a initial key pair of multisig2 before the account key update 79 multisig2Initial, err := createAnonymousAccount("cc113e82881499a7a361e8354a5b68f6c6885c7bcba09ea2b0891480396c322e") 80 assert.Equal(t, nil, err) 81 82 multisig, err := createMultisigAccount(uint(2), 83 []uint{1, 1, 1}, 84 []string{ 85 "bb113e82881499a7a361e8354a5b68f6c6885c7bcba09ea2b0891480396c322e", 86 "a5c9a50938a089618167c9d67dbebc0deaffc3c76ddc6b40c2777ae59438e989", 87 "c32c471b732e2f56103e2f8e8cfd52792ef548f05f326e546a7d1fbf9d0419ec", 88 }, 89 multisigInitial.Addr) 90 91 multisig2, err := createMultisigAccount(uint(2), 92 []uint{1, 1, 1}, 93 []string{ 94 "bb113e82881499a7a361e8354a5b68f6c6885c7bcba09ea2b0891480396c322f", 95 "a5c9a50938a089618167c9d67dbebc0deaffc3c76ddc6b40c2777ae59438e98a", 96 "c32c471b732e2f56103e2f8e8cfd52792ef548f05f326e546a7d1fbf9d0419ed", 97 }, 98 multisig2Initial.Addr) 99 100 signer := types.LatestSignerForChainID(bcdata.bc.Config().ChainID) 101 gasPrice := new(big.Int).SetUint64(bcdata.bc.Config().UnitPrice) 102 103 // Transfer (reservoir -> multisig) using a legacy transaction. 104 { 105 var txs types.Transactions 106 107 amount := new(big.Int).Mul(big.NewInt(3000), new(big.Int).SetUint64(params.KLAY)) 108 tx := types.NewTransaction(reservoir.Nonce, 109 multisig.Addr, amount, gasLimit, gasPrice, []byte{}) 110 111 err := tx.SignWithKeys(signer, reservoir.Keys) 112 assert.Equal(t, nil, err) 113 txs = append(txs, tx) 114 115 if err := bcdata.GenABlockWithTransactions(accountMap, txs, prof); err != nil { 116 t.Fatal(err) 117 } 118 reservoir.Nonce += 1 119 } 120 121 // Update multisig account's key to a multisig key 122 { 123 var txs types.Transactions 124 125 values := map[types.TxValueKeyType]interface{}{ 126 types.TxValueKeyNonce: multisig.Nonce, 127 types.TxValueKeyFrom: multisig.Addr, 128 types.TxValueKeyGasLimit: gasLimit, 129 types.TxValueKeyGasPrice: gasPrice, 130 types.TxValueKeyAccountKey: multisig.AccKey, 131 } 132 tx, err := types.NewTransactionWithMap(types.TxTypeAccountUpdate, values) 133 assert.Equal(t, nil, err) 134 135 err = tx.SignWithKeys(signer, multisigInitial.Keys) 136 assert.Equal(t, nil, err) 137 138 txs = append(txs, tx) 139 140 if err := bcdata.GenABlockWithTransactions(accountMap, txs, prof); err != nil { 141 t.Fatal(err) 142 } 143 multisig.Nonce += 1 144 } 145 146 // Transfer (reservoir -> multisig2) using a legacy transaction. 147 { 148 var txs types.Transactions 149 150 amount := new(big.Int).Mul(big.NewInt(3000), new(big.Int).SetUint64(params.KLAY)) 151 tx := types.NewTransaction(reservoir.Nonce, 152 multisig2.Addr, amount, gasLimit, gasPrice, []byte{}) 153 154 err := tx.SignWithKeys(signer, reservoir.Keys) 155 assert.Equal(t, nil, err) 156 txs = append(txs, tx) 157 158 if err := bcdata.GenABlockWithTransactions(accountMap, txs, prof); err != nil { 159 t.Fatal(err) 160 } 161 reservoir.Nonce += 1 162 } 163 164 // Update multisig2 account's key to a multisig key 165 { 166 var txs types.Transactions 167 168 values := map[types.TxValueKeyType]interface{}{ 169 types.TxValueKeyNonce: multisig2.Nonce, 170 types.TxValueKeyFrom: multisig2.Addr, 171 types.TxValueKeyGasLimit: gasLimit, 172 types.TxValueKeyGasPrice: gasPrice, 173 types.TxValueKeyAccountKey: multisig2.AccKey, 174 } 175 tx, err := types.NewTransactionWithMap(types.TxTypeAccountUpdate, values) 176 assert.Equal(t, nil, err) 177 178 err = tx.SignWithKeys(signer, multisig2Initial.Keys) 179 assert.Equal(t, nil, err) 180 181 txs = append(txs, tx) 182 183 if err := bcdata.GenABlockWithTransactions(accountMap, txs, prof); err != nil { 184 t.Fatal(err) 185 } 186 multisig.Nonce += 1 187 } 188 189 // Deploy the contract `ValidateSender`. 190 start = time.Now() 191 filepath := "../contracts/validatesender/validate_sender.sol" 192 contracts, err := deployContract(filepath, bcdata, accountMap, prof) 193 if err != nil { 194 t.Fatal(err) 195 } 196 prof.Profile("main_deployContract", time.Now().Sub(start)) 197 198 c := contracts["../contracts/validatesender/validate_sender.sol:ValidateSenderContract"] 199 abii, err := abi.JSON(strings.NewReader(c.abi)) 200 assert.Equal(t, nil, err) 201 202 n := accountMap.GetNonce(*bcdata.addrs[0]) 203 204 // Check if the validation is successful with valid parameters of multisig. 205 { 206 msg := crypto.Keccak256Hash([]byte{0x1}) 207 sigs := make([]byte, 65*2) 208 s1, err := crypto.Sign(msg[:], multisig.Keys[0]) 209 assert.Equal(t, nil, err) 210 s2, err := crypto.Sign(msg[:], multisig.Keys[1]) 211 assert.Equal(t, nil, err) 212 213 copy(sigs[0:65], s1[0:65]) 214 copy(sigs[65:130], s2[0:65]) 215 216 data, err := abii.Pack("ValidateSender", multisig.Addr, msg, sigs) 217 if err != nil { 218 t.Fatal(err) 219 } 220 221 tx, err := types.NewTransactionWithMap(types.TxTypeSmartContractExecution, map[types.TxValueKeyType]interface{}{ 222 types.TxValueKeyNonce: n, 223 types.TxValueKeyGasPrice: big.NewInt(0), 224 types.TxValueKeyGasLimit: uint64(5000000), 225 types.TxValueKeyFrom: *bcdata.addrs[0], 226 types.TxValueKeyAmount: big.NewInt(0), 227 types.TxValueKeyTo: c.address, 228 types.TxValueKeyData: data, 229 }) 230 assert.Equal(t, nil, err) 231 232 err = tx.Sign(signer, bcdata.privKeys[0]) 233 assert.Equal(t, nil, err) 234 235 // 3. Call the given function `ValidateSender`. 236 ret, err := callContract(bcdata, tx) 237 assert.Equal(t, nil, err) 238 239 // 4. Check the returned value. 240 var validated bool 241 if err := abii.UnpackIntoInterface(&validated, "ValidateSender", ret); err != nil { 242 t.Fatal(err) 243 } 244 assert.Equal(t, true, validated) 245 } 246 247 // Check if the validation is successful with valid parameters of reservoir. 248 { 249 msg := crypto.Keccak256Hash([]byte{0x1}) 250 sigs := make([]byte, 65) 251 s1, err := crypto.Sign(msg[:], reservoir.Keys[0]) 252 assert.Equal(t, nil, err) 253 254 copy(sigs[0:65], s1[0:65]) 255 256 data, err := abii.Pack("ValidateSender", reservoir.Addr, msg, sigs) 257 if err != nil { 258 t.Fatal(err) 259 } 260 261 tx, err := types.NewTransactionWithMap(types.TxTypeSmartContractExecution, map[types.TxValueKeyType]interface{}{ 262 types.TxValueKeyNonce: n, 263 types.TxValueKeyGasPrice: big.NewInt(0), 264 types.TxValueKeyGasLimit: uint64(5000000), 265 types.TxValueKeyFrom: *bcdata.addrs[0], 266 types.TxValueKeyAmount: big.NewInt(0), 267 types.TxValueKeyTo: c.address, 268 types.TxValueKeyData: data, 269 }) 270 assert.Equal(t, nil, err) 271 272 err = tx.Sign(signer, bcdata.privKeys[0]) 273 assert.Equal(t, nil, err) 274 275 // 3. Call the given function `ValidateSender`. 276 ret, err := callContract(bcdata, tx) 277 assert.Equal(t, nil, err) 278 279 // 4. Check the returned value. 280 var validated bool 281 if err := abii.UnpackIntoInterface(&validated, "ValidateSender", ret); err != nil { 282 t.Fatal(err) 283 } 284 assert.Equal(t, true, validated) 285 } 286 287 // Check if the validation is failed with wrong signature. 288 { 289 msg := crypto.Keccak256Hash([]byte{0x1}) 290 sigs := make([]byte, 65) 291 s1, err := crypto.Sign(msg[:], multisig.Keys[0]) 292 assert.Equal(t, nil, err) 293 294 copy(sigs[0:65], s1[0:65]) 295 296 data, err := abii.Pack("ValidateSender", multisig.Addr, msg, sigs) 297 if err != nil { 298 t.Fatal(err) 299 } 300 301 tx, err := types.NewTransactionWithMap(types.TxTypeSmartContractExecution, map[types.TxValueKeyType]interface{}{ 302 types.TxValueKeyNonce: n, 303 types.TxValueKeyGasPrice: big.NewInt(0), 304 types.TxValueKeyGasLimit: uint64(5000000), 305 types.TxValueKeyFrom: *bcdata.addrs[0], 306 types.TxValueKeyAmount: big.NewInt(0), 307 types.TxValueKeyTo: c.address, 308 types.TxValueKeyData: data, 309 }) 310 assert.Equal(t, nil, err) 311 312 err = tx.Sign(signer, bcdata.privKeys[0]) 313 assert.Equal(t, nil, err) 314 315 // 3. Call the given function `ValidateSender`. 316 ret, err := callContract(bcdata, tx) 317 assert.Equal(t, nil, err) 318 319 // 4. Check the returned value. 320 var validated bool 321 if err := abii.UnpackIntoInterface(&validated, "ValidateSender", ret); err != nil { 322 t.Fatal(err) 323 } 324 assert.Equal(t, false, validated) 325 } 326 327 // Check if the validation is failed with signed by multisig but the address was set to mulsig2. 328 { 329 msg := crypto.Keccak256Hash([]byte{0x1}) 330 sigs := make([]byte, 65*2) 331 s1, err := crypto.Sign(msg[:], multisig.Keys[0]) 332 assert.Equal(t, nil, err) 333 s2, err := crypto.Sign(msg[:], multisig.Keys[1]) 334 assert.Equal(t, nil, err) 335 336 copy(sigs[0:65], s1[0:65]) 337 copy(sigs[65:130], s2[0:65]) 338 339 data, err := abii.Pack("ValidateSender", multisig2.Addr, msg, sigs) 340 if err != nil { 341 t.Fatal(err) 342 } 343 344 tx, err := types.NewTransactionWithMap(types.TxTypeSmartContractExecution, map[types.TxValueKeyType]interface{}{ 345 types.TxValueKeyNonce: n, 346 types.TxValueKeyGasPrice: big.NewInt(0), 347 types.TxValueKeyGasLimit: uint64(5000000), 348 types.TxValueKeyFrom: *bcdata.addrs[0], 349 types.TxValueKeyAmount: big.NewInt(0), 350 types.TxValueKeyTo: c.address, 351 types.TxValueKeyData: data, 352 }) 353 assert.Equal(t, nil, err) 354 355 err = tx.Sign(signer, bcdata.privKeys[0]) 356 assert.Equal(t, nil, err) 357 358 // 3. Call the given function `ValidateSender`. 359 ret, err := callContract(bcdata, tx) 360 assert.Equal(t, nil, err) 361 362 // 4. Check the returned value. 363 var validated bool 364 if err := abii.UnpackIntoInterface(&validated, "ValidateSender", ret); err != nil { 365 t.Fatal(err) 366 } 367 assert.Equal(t, false, validated) 368 } 369 370 // Check if the validation is failed with an unknown address. 371 { 372 msg := crypto.Keccak256Hash([]byte{0x1}) 373 sigs := make([]byte, 65*2) 374 s1, err := crypto.Sign(msg[:], multisig.Keys[0]) 375 assert.Equal(t, nil, err) 376 s2, err := crypto.Sign(msg[:], multisig.Keys[1]) 377 assert.Equal(t, nil, err) 378 379 copy(sigs[0:65], s1[0:65]) 380 copy(sigs[65:130], s2[0:65]) 381 382 var addr common.Address 383 addr.SetBytesFromFront([]byte(getRandomPrivateKeyString(t))) 384 385 data, err := abii.Pack("ValidateSender", addr, msg, sigs) 386 if err != nil { 387 t.Fatal(err) 388 } 389 390 tx, err := types.NewTransactionWithMap(types.TxTypeSmartContractExecution, map[types.TxValueKeyType]interface{}{ 391 types.TxValueKeyNonce: n, 392 types.TxValueKeyGasPrice: big.NewInt(0), 393 types.TxValueKeyGasLimit: uint64(5000000), 394 types.TxValueKeyFrom: *bcdata.addrs[0], 395 types.TxValueKeyAmount: big.NewInt(0), 396 types.TxValueKeyTo: c.address, 397 types.TxValueKeyData: data, 398 }) 399 assert.Equal(t, nil, err) 400 401 err = tx.Sign(signer, bcdata.privKeys[0]) 402 assert.Equal(t, nil, err) 403 404 // 3. Call the given function `ValidateSender`. 405 ret, err := callContract(bcdata, tx) 406 assert.Equal(t, nil, err) 407 408 // 4. Check the returned value. 409 var validated bool 410 if err := abii.UnpackIntoInterface(&validated, "ValidateSender", ret); err != nil { 411 t.Fatal(err) 412 } 413 assert.Equal(t, false, validated) 414 } 415 }