github.com/klaytn/klaytn@v1.12.1/tests/hard_fork_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 "encoding/json" 22 "fmt" 23 "math/big" 24 "os" 25 "strings" 26 "testing" 27 "time" 28 29 "github.com/klaytn/klaytn/blockchain" 30 "github.com/klaytn/klaytn/blockchain/types" 31 "github.com/klaytn/klaytn/blockchain/vm" 32 "github.com/klaytn/klaytn/common" 33 "github.com/klaytn/klaytn/common/hexutil" 34 "github.com/klaytn/klaytn/common/profile" 35 "github.com/klaytn/klaytn/consensus/istanbul" 36 "github.com/klaytn/klaytn/crypto" 37 "github.com/klaytn/klaytn/governance" 38 "github.com/klaytn/klaytn/log" 39 "github.com/klaytn/klaytn/params" 40 "github.com/klaytn/klaytn/rlp" 41 "github.com/klaytn/klaytn/storage/database" 42 "github.com/stretchr/testify/assert" 43 "github.com/stretchr/testify/require" 44 45 istanbulBackend "github.com/klaytn/klaytn/consensus/istanbul/backend" 46 ) 47 48 // TestHardForkBlock tests whether the change incurs a hard fork or not. 49 // genesis.json, b1.rlp, and b2.rlp has raw data of genesis, and consecutive two blocks after the genesis block. 50 // If anything is failed, it can be considered that a hard fork occurs. 51 func TestHardForkBlock(t *testing.T) { 52 log.EnableLogForTest(log.LvlCrit, log.LvlTrace) 53 var genesis blockchain.Genesis 54 55 // If you uncomment the below, you can find this test failed with an error "!!!!!HARD FORK DETECTED!!!!!" 56 //fork.UpdateHardForkConfig(&fork.HardForkConfig{ 57 //}) 58 59 // If you print out b1.rlp and b2.rlp, uncomment below. 60 // `genBlocks` could be failed sometimes depends on the order of transaction in a block. Just try again. 61 // genBlocks(t) 62 // return 63 64 // load raw data from files. 65 genesisJson, err := os.ReadFile("genesis.json") 66 require.Equal(t, nil, err) 67 rawb1, err := os.ReadFile("b1.rlp") 68 require.Equal(t, nil, err) 69 rawb2, err := os.ReadFile("b2.rlp") 70 require.Equal(t, nil, err) 71 72 err = json.Unmarshal([]byte(genesisJson), &genesis) 73 require.Equal(t, nil, err) 74 75 genesisKey, err := crypto.HexToECDSA("42eb1412d77987043716f425964b1c8d4c27ce9fb3e9a5b9ab243bc9882fe731") 76 require.Equal(t, nil, err) 77 78 var genesisAddr common.Address 79 for addr := range genesis.Alloc { 80 genesisAddr = addr 81 break 82 } 83 84 dir := "chaindata-hardfork" 85 os.RemoveAll(dir) 86 87 chainDb := NewDatabase(dir, database.LevelDB) 88 defer func() { 89 os.RemoveAll(dir) 90 }() 91 92 gov := generateGovernaceDataForTest() 93 chainConfig, _, err := blockchain.SetupGenesisBlock(chainDb, &genesis, params.UnusedNetworkId, false, false) 94 governance.AddGovernanceCacheForTest(gov, 0, genesis.Config) 95 engine := istanbulBackend.New(&istanbulBackend.BackendOpts{ 96 IstanbulConfig: istanbul.DefaultConfig, 97 Rewardbase: genesisAddr, 98 PrivateKey: genesisKey, 99 DB: chainDb, 100 Governance: gov, 101 NodeType: common.CONSENSUSNODE, 102 }) 103 chain, err := blockchain.NewBlockChain(chainDb, nil, chainConfig, engine, vm.Config{}) 104 105 r1, err := hexutil.Decode(string(rawb1)) 106 require.Equal(t, nil, err) 107 r2, err := hexutil.Decode(string(rawb2)) 108 require.Equal(t, nil, err) 109 rawBlocks := [...][]byte{r1, r2} 110 111 var blocks types.Blocks 112 for _, raw := range rawBlocks { 113 var blk types.Block 114 115 err := rlp.DecodeBytes(raw, &blk) 116 require.Equal(t, nil, err) 117 118 blocks = append(blocks, &blk) 119 } 120 121 idx, err := chain.InsertChain(blocks) 122 require.Equalf(t, nil, err, "!!!!!HARD FORK DETECTED!!!!!") 123 require.Equal(t, 0, idx) 124 } 125 126 // genBlock generates two blocks including transactions utilizing all transaction types and account types. 127 func genBlocks(t *testing.T) { 128 testFunctions := []struct { 129 Name string 130 genTx genTransaction 131 }{ 132 {"LegacyTransaction", genLegacyTransaction}, 133 {"ValueTransfer", genValueTransfer}, 134 {"ValueTransferWithMemo", genValueTransferWithMemo}, 135 {"AccountUpdate", genAccountUpdateIdem}, 136 {"SmartContractExecution", genSmartContractExecution}, 137 {"Cancel", genCancel}, 138 {"ChainDataAnchoring", genChainDataAnchoring}, 139 {"FeeDelegatedValueTransfer", genFeeDelegatedValueTransfer}, 140 {"FeeDelegatedValueTransferWithMemo", genFeeDelegatedValueTransferWithMemo}, 141 {"FeeDelegatedAccountUpdate", genFeeDelegatedAccountUpdateIdem}, 142 {"FeeDelegatedSmartContractExecution", genFeeDelegatedSmartContractExecution}, 143 {"FeeDelegatedCancel", genFeeDelegatedCancel}, 144 {"FeeDelegatedWithRatioValueTransfer", genFeeDelegatedWithRatioValueTransfer}, 145 {"FeeDelegatedWithRatioValueTransferWithMemo", genFeeDelegatedWithRatioValueTransferWithMemo}, 146 {"FeeDelegatedWithRatioAccountUpdate", genFeeDelegatedWithRatioAccountUpdateIdem}, 147 {"FeeDelegatedWithRatioSmartContractExecution", genFeeDelegatedWithRatioSmartContractExecution}, 148 {"FeeDelegatedWithRatioCancel", genFeeDelegatedWithRatioCancel}, 149 } 150 151 accountTypes := []struct { 152 Type string 153 account TestAccount 154 }{ 155 {"KlaytnLegacy", genKlaytnLegacyAccount(t)}, 156 {"Public", genPublicAccount(t)}, 157 {"MultiSig", genMultiSigAccount(t)}, 158 {"RoleBasedWithPublic", genRoleBasedWithPublicAccount(t)}, 159 {"RoleBasedWithMultiSig", genRoleBasedWithMultiSigAccount(t)}, 160 } 161 162 log.EnableLogForTest(log.LvlCrit, log.LvlTrace) 163 prof := profile.NewProfiler() 164 165 // Initialize blockchain 166 start := time.Now() 167 bcdata, err := NewBCData(6, 4) 168 assert.Equal(t, nil, err) 169 prof.Profile("main_init_blockchain", time.Now().Sub(start)) 170 171 b, err := json.Marshal(bcdata.genesis) 172 os.WriteFile("genesis.json", b, 0o755) 173 174 defer bcdata.Shutdown() 175 176 // Initialize address-balance map for verification 177 start = time.Now() 178 accountMap := NewAccountMap() 179 if err := accountMap.Initialize(bcdata); err != nil { 180 t.Fatal(err) 181 } 182 prof.Profile("main_init_accountMap", time.Now().Sub(start)) 183 184 // reservoir account 185 var reservoir TestAccount 186 reservoir = &TestAccountType{ 187 Addr: *bcdata.addrs[0], 188 Keys: []*ecdsa.PrivateKey{bcdata.privKeys[0]}, 189 Nonce: uint64(0), 190 } 191 192 signer := types.LatestSignerForChainID(bcdata.bc.Config().ChainID) 193 gasPrice := new(big.Int).SetUint64(bcdata.bc.Config().UnitPrice) 194 195 // For smart contract 196 contract, err := createAnonymousAccount("ed34b0cf47a0021e9897760f0a904a69260c2f638e0bcc805facb745ec3ff9ab") 197 assert.Equal(t, nil, err) 198 199 // Preparing step 200 { 201 var txs types.Transactions 202 // Preparing step. Send KLAY to LegacyAccount. 203 { 204 amount := new(big.Int).Mul(big.NewInt(3000), new(big.Int).SetUint64(params.KLAY)) 205 tx := types.NewTransaction(reservoir.GetNonce(), 206 accountTypes[0].account.GetAddr(), amount, gasLimit, gasPrice, []byte{}) 207 208 err := tx.SignWithKeys(signer, reservoir.GetTxKeys()) 209 assert.Equal(t, nil, err) 210 211 txs = append(txs, tx) 212 213 reservoir.AddNonce() 214 } 215 216 // Preparing step. Send KLAY to KlaytnAcounts. 217 for i := 1; i < len(accountTypes); i++ { 218 // create an account which account key will be replaced to one of account key types. 219 anon, err := createAnonymousAccount(getRandomPrivateKeyString(t)) 220 assert.Equal(t, nil, err) 221 222 accountTypes[i].account.SetAddr(anon.Addr) 223 224 { 225 amount := new(big.Int).Mul(big.NewInt(3000), new(big.Int).SetUint64(params.KLAY)) 226 tx := types.NewTransaction(reservoir.GetNonce(), 227 accountTypes[i].account.GetAddr(), amount, gasLimit, gasPrice, []byte{}) 228 229 err := tx.SignWithKeys(signer, reservoir.GetTxKeys()) 230 assert.Equal(t, nil, err) 231 txs = append(txs, tx) 232 233 reservoir.AddNonce() 234 } 235 236 // update the account's key 237 { 238 values := map[types.TxValueKeyType]interface{}{ 239 types.TxValueKeyNonce: accountTypes[i].account.GetNonce(), 240 types.TxValueKeyFrom: accountTypes[i].account.GetAddr(), 241 types.TxValueKeyGasLimit: gasLimit, 242 types.TxValueKeyGasPrice: gasPrice, 243 types.TxValueKeyAccountKey: accountTypes[i].account.GetAccKey(), 244 } 245 tx, err := types.NewTransactionWithMap(types.TxTypeAccountUpdate, values) 246 assert.Equal(t, nil, err) 247 248 err = tx.SignWithKeys(signer, anon.Keys) 249 assert.Equal(t, nil, err) 250 251 txs = append(txs, tx) 252 253 accountTypes[i].account.AddNonce() 254 } 255 } 256 257 { 258 amount := new(big.Int).SetUint64(0) 259 260 values := map[types.TxValueKeyType]interface{}{ 261 types.TxValueKeyNonce: reservoir.GetNonce(), 262 types.TxValueKeyFrom: reservoir.GetAddr(), 263 types.TxValueKeyTo: (*common.Address)(nil), 264 types.TxValueKeyAmount: amount, 265 types.TxValueKeyGasLimit: gasLimit, 266 types.TxValueKeyGasPrice: gasPrice, 267 types.TxValueKeyHumanReadable: false, 268 types.TxValueKeyData: common.FromHex(code), 269 types.TxValueKeyCodeFormat: params.CodeFormatEVM, 270 } 271 tx, err := types.NewTransactionWithMap(types.TxTypeSmartContractDeploy, values) 272 assert.Equal(t, nil, err) 273 274 err = tx.SignWithKeys(signer, reservoir.GetTxKeys()) 275 assert.Equal(t, nil, err) 276 277 txs = append(txs, tx) 278 279 contract.Addr = crypto.CreateAddress(reservoir.GetAddr(), reservoir.GetNonce()) 280 281 reservoir.AddNonce() 282 } 283 { 284 amount := new(big.Int).SetUint64(0) 285 286 values := map[types.TxValueKeyType]interface{}{ 287 types.TxValueKeyNonce: reservoir.GetNonce(), 288 types.TxValueKeyFrom: reservoir.GetAddr(), 289 types.TxValueKeyTo: (*common.Address)(nil), 290 types.TxValueKeyAmount: amount, 291 types.TxValueKeyGasLimit: gasLimit, 292 types.TxValueKeyGasPrice: gasPrice, 293 types.TxValueKeyHumanReadable: false, 294 types.TxValueKeyData: common.FromHex(code), 295 types.TxValueKeyFeePayer: reservoir.GetAddr(), 296 types.TxValueKeyCodeFormat: params.CodeFormatEVM, 297 } 298 tx, err := types.NewTransactionWithMap(types.TxTypeFeeDelegatedSmartContractDeploy, values) 299 assert.Equal(t, nil, err) 300 301 err = tx.SignWithKeys(signer, reservoir.GetTxKeys()) 302 assert.Equal(t, nil, err) 303 304 err = tx.SignFeePayerWithKeys(signer, reservoir.GetFeeKeys()) 305 assert.Equal(t, nil, err) 306 307 txs = append(txs, tx) 308 309 reservoir.AddNonce() 310 } 311 { 312 amount := new(big.Int).SetUint64(0) 313 314 values := map[types.TxValueKeyType]interface{}{ 315 types.TxValueKeyNonce: reservoir.GetNonce(), 316 types.TxValueKeyFrom: reservoir.GetAddr(), 317 types.TxValueKeyTo: (*common.Address)(nil), 318 types.TxValueKeyAmount: amount, 319 types.TxValueKeyGasLimit: gasLimit, 320 types.TxValueKeyGasPrice: gasPrice, 321 types.TxValueKeyHumanReadable: false, 322 types.TxValueKeyData: common.FromHex(code), 323 types.TxValueKeyFeePayer: reservoir.GetAddr(), 324 types.TxValueKeyFeeRatioOfFeePayer: types.FeeRatio(20), 325 types.TxValueKeyCodeFormat: params.CodeFormatEVM, 326 } 327 tx, err := types.NewTransactionWithMap(types.TxTypeFeeDelegatedSmartContractDeployWithRatio, values) 328 assert.Equal(t, nil, err) 329 330 err = tx.SignWithKeys(signer, reservoir.GetTxKeys()) 331 assert.Equal(t, nil, err) 332 333 err = tx.SignFeePayerWithKeys(signer, reservoir.GetFeeKeys()) 334 assert.Equal(t, nil, err) 335 336 txs = append(txs, tx) 337 338 reservoir.AddNonce() 339 } 340 341 // SmartContractDeploy with Nil Recipient. 342 { 343 amount := new(big.Int).SetUint64(0) 344 345 values := map[types.TxValueKeyType]interface{}{ 346 types.TxValueKeyNonce: reservoir.GetNonce(), 347 types.TxValueKeyFrom: reservoir.GetAddr(), 348 types.TxValueKeyTo: (*common.Address)(nil), 349 types.TxValueKeyAmount: amount, 350 types.TxValueKeyGasLimit: gasLimit, 351 types.TxValueKeyGasPrice: gasPrice, 352 types.TxValueKeyHumanReadable: false, 353 types.TxValueKeyData: common.FromHex(code), 354 types.TxValueKeyCodeFormat: params.CodeFormatEVM, 355 } 356 tx, err := types.NewTransactionWithMap(types.TxTypeSmartContractDeploy, values) 357 assert.Equal(t, nil, err) 358 359 err = tx.SignWithKeys(signer, reservoir.GetTxKeys()) 360 assert.Equal(t, nil, err) 361 362 txs = append(txs, tx) 363 364 reservoir.AddNonce() 365 } 366 { 367 amount := new(big.Int).SetUint64(0) 368 369 values := map[types.TxValueKeyType]interface{}{ 370 types.TxValueKeyNonce: reservoir.GetNonce(), 371 types.TxValueKeyFrom: reservoir.GetAddr(), 372 types.TxValueKeyTo: (*common.Address)(nil), 373 types.TxValueKeyAmount: amount, 374 types.TxValueKeyGasLimit: gasLimit, 375 types.TxValueKeyGasPrice: gasPrice, 376 types.TxValueKeyHumanReadable: false, 377 types.TxValueKeyData: common.FromHex(code), 378 types.TxValueKeyFeePayer: reservoir.GetAddr(), 379 types.TxValueKeyCodeFormat: params.CodeFormatEVM, 380 } 381 tx, err := types.NewTransactionWithMap(types.TxTypeFeeDelegatedSmartContractDeploy, values) 382 assert.Equal(t, nil, err) 383 384 err = tx.SignWithKeys(signer, reservoir.GetTxKeys()) 385 assert.Equal(t, nil, err) 386 387 err = tx.SignFeePayerWithKeys(signer, reservoir.GetFeeKeys()) 388 assert.Equal(t, nil, err) 389 390 txs = append(txs, tx) 391 392 reservoir.AddNonce() 393 } 394 { 395 amount := new(big.Int).SetUint64(0) 396 397 values := map[types.TxValueKeyType]interface{}{ 398 types.TxValueKeyNonce: reservoir.GetNonce(), 399 types.TxValueKeyFrom: reservoir.GetAddr(), 400 types.TxValueKeyTo: (*common.Address)(nil), 401 types.TxValueKeyAmount: amount, 402 types.TxValueKeyGasLimit: gasLimit, 403 types.TxValueKeyGasPrice: gasPrice, 404 types.TxValueKeyHumanReadable: false, 405 types.TxValueKeyData: common.FromHex(code), 406 types.TxValueKeyFeePayer: reservoir.GetAddr(), 407 types.TxValueKeyFeeRatioOfFeePayer: types.FeeRatio(20), 408 types.TxValueKeyCodeFormat: params.CodeFormatEVM, 409 } 410 tx, err := types.NewTransactionWithMap(types.TxTypeFeeDelegatedSmartContractDeployWithRatio, values) 411 assert.Equal(t, nil, err) 412 413 err = tx.SignWithKeys(signer, reservoir.GetTxKeys()) 414 assert.Equal(t, nil, err) 415 416 err = tx.SignFeePayerWithKeys(signer, reservoir.GetFeeKeys()) 417 assert.Equal(t, nil, err) 418 419 txs = append(txs, tx) 420 421 reservoir.AddNonce() 422 } 423 424 if err := bcdata.GenABlockWithTransactions(accountMap, txs, prof); err != nil { 425 t.Fatal(err) 426 } 427 } 428 429 var txs types.Transactions 430 431 for _, f := range testFunctions { 432 for _, sender := range accountTypes { 433 toAccount := reservoir 434 435 // LegacyTransaction can be used only with LegacyAccount and KlaytnAccount with AccountKeyLegacy. 436 if !strings.Contains(sender.Type, "Legacy") && strings.Contains(f.Name, "Legacy") { 437 continue 438 } 439 440 // Sender can't be a LegacyAccount with AccountUpdate 441 if sender.Type == "Legacy" && strings.Contains(f.Name, "AccountUpdate") { 442 continue 443 } 444 445 gasPriceLocal := gasPrice 446 // Set contract's address with SmartContractExecution 447 if strings.Contains(f.Name, "SmartContractExecution") { 448 toAccount = contract 449 gasPriceLocal = big.NewInt(0) 450 } 451 452 if !strings.Contains(f.Name, "FeeDelegated") { 453 // For NonFeeDelegated Transactions 454 tx, _ := f.genTx(t, signer, sender.account, toAccount, nil, gasPriceLocal) 455 txs = append(txs, tx) 456 sender.account.AddNonce() 457 } else { 458 // For FeeDelegated(WithRatio) Transactions 459 for _, payer := range accountTypes { 460 tx, _ := f.genTx(t, signer, sender.account, toAccount, payer.account, gasPriceLocal) 461 txs = append(txs, tx) 462 sender.account.AddNonce() 463 } 464 } 465 } 466 } 467 468 if err := bcdata.GenABlockWithTransactions(accountMap, txs, prof); err != nil { 469 t.Fatal(err) 470 } 471 472 lastBlock := bcdata.bc.CurrentBlock().NumberU64() 473 for i := uint64(0); i <= lastBlock; i++ { 474 blk := bcdata.bc.GetBlockByNumber(i) 475 b, err := rlp.EncodeToBytes(blk) 476 require.Equal(t, nil, err) 477 478 // fmt.Println(blk.String()) 479 // fmt.Println("encoded===") 480 // fmt.Println((hexutil.Bytes)(b)) 481 482 filename := fmt.Sprintf("b%d.rlp", i) 483 f, err := os.Create(filename) 484 require.Equal(t, nil, err) 485 486 _, err = f.WriteString(hexutil.Encode(b)) 487 require.Equal(t, nil, err) 488 489 err = f.Close() 490 require.Equal(t, nil, err) 491 } 492 } 493 494 func genAccountUpdateIdem(t *testing.T, signer types.Signer, from TestAccount, to TestAccount, payer TestAccount, gasPrice *big.Int) (*types.Transaction, uint64) { 495 values, intrinsic := genMapForUpdate(from, to, gasPrice, from.GetAccKey(), types.TxTypeAccountUpdate) 496 497 tx, err := types.NewTransactionWithMap(types.TxTypeAccountUpdate, values) 498 assert.Equal(t, nil, err) 499 500 err = tx.SignWithKeys(signer, from.GetUpdateKeys()) 501 assert.Equal(t, nil, err) 502 503 return tx, intrinsic 504 } 505 506 func genFeeDelegatedAccountUpdateIdem(t *testing.T, signer types.Signer, from TestAccount, to TestAccount, payer TestAccount, gasPrice *big.Int) (*types.Transaction, uint64) { 507 values, intrinsic := genMapForUpdate(from, to, gasPrice, from.GetAccKey(), types.TxTypeFeeDelegatedAccountUpdate) 508 values[types.TxValueKeyFeePayer] = payer.GetAddr() 509 510 tx, err := types.NewTransactionWithMap(types.TxTypeFeeDelegatedAccountUpdate, values) 511 assert.Equal(t, nil, err) 512 513 err = tx.SignWithKeys(signer, from.GetUpdateKeys()) 514 assert.Equal(t, nil, err) 515 516 err = tx.SignFeePayerWithKeys(signer, payer.GetFeeKeys()) 517 assert.Equal(t, nil, err) 518 519 return tx, intrinsic 520 } 521 522 func genFeeDelegatedWithRatioAccountUpdateIdem(t *testing.T, signer types.Signer, from TestAccount, to TestAccount, payer TestAccount, gasPrice *big.Int) (*types.Transaction, uint64) { 523 values, intrinsic := genMapForUpdate(from, to, gasPrice, from.GetAccKey(), types.TxTypeFeeDelegatedAccountUpdateWithRatio) 524 values[types.TxValueKeyFeePayer] = payer.GetAddr() 525 values[types.TxValueKeyFeeRatioOfFeePayer] = types.FeeRatio(30) 526 527 tx, err := types.NewTransactionWithMap(types.TxTypeFeeDelegatedAccountUpdateWithRatio, values) 528 assert.Equal(t, nil, err) 529 530 err = tx.SignWithKeys(signer, from.GetUpdateKeys()) 531 assert.Equal(t, nil, err) 532 533 err = tx.SignFeePayerWithKeys(signer, payer.GetFeeKeys()) 534 assert.Equal(t, nil, err) 535 536 return tx, intrinsic 537 }