|
| 1 | +#include <boost/test/unit_test.hpp> |
| 2 | +#include <qtumtests/test_utils.h> |
| 3 | +#include <qtum/qtumutils.h> |
| 4 | +#include <chainparams.h> |
| 5 | + |
| 6 | +namespace CancunTest{ |
| 7 | + |
| 8 | +const dev::u256 GASLIMIT = dev::u256(500000); |
| 9 | +const dev::h256 HASHTX = dev::h256(ParseHex("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")); |
| 10 | + |
| 11 | +// Codes used to check that cancun fork |
| 12 | +const std::vector<valtype> CODE = { |
| 13 | + /* |
| 14 | + pragma solidity ^0.8.24; |
| 15 | +
|
| 16 | + contract MulService { |
| 17 | + function setMultiplier(uint multiplier) external { |
| 18 | + assembly { |
| 19 | + tstore(0, multiplier) |
| 20 | + } |
| 21 | + } |
| 22 | +
|
| 23 | + function getMultiplier() private view returns (uint multiplier) { |
| 24 | + assembly { |
| 25 | + multiplier := tload(0) |
| 26 | + } |
| 27 | + } |
| 28 | +
|
| 29 | + function multiply(uint value) external view returns (uint) { |
| 30 | + return value * getMultiplier(); |
| 31 | + } |
| 32 | + } |
| 33 | + */ valtype(ParseHex("6080604052348015600e575f80fd5b506101db8061001c5f395ff3fe608060405234801561000f575f80fd5b5060043610610034575f3560e01c8063641579a614610038578063c6888fa114610054575b5f80fd5b610052600480360381019061004d91906100e4565b610084565b005b61006e600480360381019061006991906100e4565b61008a565b60405161007b919061011e565b60405180910390f35b805f5d50565b5f6100936100a5565b8261009e9190610164565b9050919050565b5f805c905090565b5f80fd5b5f819050919050565b6100c3816100b1565b81146100cd575f80fd5b50565b5f813590506100de816100ba565b92915050565b5f602082840312156100f9576100f86100ad565b5b5f610106848285016100d0565b91505092915050565b610118816100b1565b82525050565b5f6020820190506101315f83018461010f565b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f61016e826100b1565b9150610179836100b1565b9250828202610187816100b1565b9150828204841483151761019e5761019d610137565b5b509291505056fea26469706673582212203dda524f45e82e20c7a5140d36ef2410c23bec4dee31ca21bc368cf508cde0f764736f6c634300081a0033")), |
| 34 | + // setMultiplier(5) |
| 35 | + valtype(ParseHex("641579a60000000000000000000000000000000000000000000000000000000000000005")), |
| 36 | + // multiply(7) |
| 37 | + valtype(ParseHex("c6888fa10000000000000000000000000000000000000000000000000000000000000007")), |
| 38 | +}; |
| 39 | +
|
| 40 | +// Codes IDs used to check that london fork is present |
| 41 | +enum class CodeID |
| 42 | +{ |
| 43 | + mulService = 0, |
| 44 | + setMultiplier_5, |
| 45 | + multiply_7, |
| 46 | +}; |
| 47 | +
|
| 48 | +// Get the code identified by the ID |
| 49 | +valtype getCode(CodeID id) |
| 50 | +{ |
| 51 | + return CODE[(int)id]; |
| 52 | +} |
| 53 | +
|
| 54 | +void genesisLoading(){ |
| 55 | + const CChainParams& chainparams = Params(); |
| 56 | + int coinbaseMaturity = Params().GetConsensus().CoinbaseMaturity(0); |
| 57 | + int forkHeight = coinbaseMaturity + 499; |
| 58 | + dev::eth::EVMConsensus evmConsensus; |
| 59 | + evmConsensus.QIP6Height = coinbaseMaturity; |
| 60 | + evmConsensus.QIP7Height = coinbaseMaturity; |
| 61 | + evmConsensus.nMuirGlacierHeight = coinbaseMaturity; |
| 62 | + evmConsensus.nLondonHeight = coinbaseMaturity; |
| 63 | + evmConsensus.nShanghaiHeight = coinbaseMaturity; |
| 64 | + evmConsensus.nCancunHeight = forkHeight; |
| 65 | + UpdateCancunHeight(forkHeight); |
| 66 | + dev::eth::ChainParams cp(chainparams.EVMGenesisInfo(evmConsensus)); |
| 67 | + globalState->populateFrom(cp.genesisState); |
| 68 | + globalSealEngine = std::unique_ptr<dev::eth::SealEngineFace>(cp.createSealEngine()); |
| 69 | + globalState->db().commit(); |
| 70 | +} |
| 71 | +
|
| 72 | +void createNewBlocks(TestChain100Setup* testChain100Setup, size_t n){ |
| 73 | + std::function<void(size_t n)> generateBlocks = [&](size_t n){ |
| 74 | + dev::h256 oldHashStateRoot = globalState->rootHash(); |
| 75 | + dev::h256 oldHashUTXORoot = globalState->rootHashUTXO(); |
| 76 | + for(size_t i = 0; i < n; i++){ |
| 77 | + testChain100Setup->CreateAndProcessBlock({}, GetScriptForRawPubKey(testChain100Setup->coinbaseKey.GetPubKey())); |
| 78 | + } |
| 79 | + globalState->setRoot(oldHashStateRoot); |
| 80 | + globalState->setRootUTXO(oldHashUTXORoot); |
| 81 | + }; |
| 82 | +
|
| 83 | + generateBlocks(n); |
| 84 | +} |
| 85 | +BOOST_FIXTURE_TEST_SUITE(cancunfork_tests, TestChain100Setup) |
| 86 | +
|
| 87 | +BOOST_AUTO_TEST_CASE(checking_transient_storage_after_fork){ |
| 88 | + genesisLoading(); |
| 89 | + createNewBlocks(this, 499); |
| 90 | + dev::h256 hashTx(HASHTX); |
| 91 | +
|
| 92 | + // Create contract |
| 93 | + std::vector<QtumTransaction> txs; |
| 94 | + txs.push_back(createQtumTransaction(getCode(CodeID::mulService), 0, GASLIMIT, dev::u256(1), ++hashTx, dev::Address())); |
| 95 | + auto result = executeBC(txs, *m_node.chainman); |
| 96 | + BOOST_CHECK(result.first[0].execRes.excepted == dev::eth::TransactionException::None); |
| 97 | +
|
| 98 | + // Create a transaction with 2 outputs that use transient storage. |
| 99 | + // The first output set the multiplier to 5. |
| 100 | + // The second output multiply the multiplier by 7, and the result is 35. |
| 101 | + dev::Address proxy = createQtumAddress(txs[0].getHashWith(), txs[0].getNVout()); |
| 102 | + std::vector<QtumTransaction> txCancun; |
| 103 | + txCancun.push_back(createQtumTransaction(getCode(CodeID::setMultiplier_5), 0, GASLIMIT, dev::u256(1), ++hashTx, proxy)); |
| 104 | + txCancun.push_back(createQtumTransaction(getCode(CodeID::multiply_7), 0, GASLIMIT, dev::u256(1), ++hashTx, proxy)); |
| 105 | + result = executeBC(txCancun, *m_node.chainman); |
| 106 | + BOOST_CHECK(result.first[0].execRes.excepted == dev::eth::TransactionException::None); |
| 107 | + BOOST_CHECK(result.first[1].execRes.excepted == dev::eth::TransactionException::None); |
| 108 | + BOOST_CHECK(result.first[0].execRes.gasUsed == 21688); |
| 109 | + BOOST_CHECK(result.first[1].execRes.gasUsed == 22179); |
| 110 | + BOOST_CHECK(result.first[0].execRes.output.size() == 0); |
| 111 | + BOOST_CHECK(result.first[1].execRes.output.size() == 32); |
| 112 | + BOOST_CHECK(dev::h256(result.first[1].execRes.output) == dev::h256(35)); |
| 113 | +
|
| 114 | + // Create a transaction with an output that use transient storage which is expired. |
| 115 | + txCancun.clear(); |
| 116 | + txCancun.push_back(createQtumTransaction(getCode(CodeID::multiply_7), 0, GASLIMIT, dev::u256(1), ++hashTx, proxy)); |
| 117 | + result = executeBC(txCancun, *m_node.chainman); |
| 118 | + BOOST_CHECK(result.first[0].execRes.excepted == dev::eth::TransactionException::None); |
| 119 | + BOOST_CHECK(result.first[0].execRes.gasUsed == 22179); |
| 120 | + BOOST_CHECK(result.first[0].execRes.output.size() == 32); |
| 121 | + BOOST_CHECK(dev::h256(result.first[0].execRes.output) == dev::h256(0)); |
| 122 | +} |
| 123 | +
|
| 124 | +BOOST_AUTO_TEST_CASE(checking_transient_storage_before_fork){ |
| 125 | + genesisLoading(); |
| 126 | + createNewBlocks(this, 498); |
| 127 | + dev::h256 hashTx(HASHTX); |
| 128 | +
|
| 129 | + // Create contract |
| 130 | + std::vector<QtumTransaction> txs; |
| 131 | + txs.push_back(createQtumTransaction(getCode(CodeID::mulService), 0, GASLIMIT, dev::u256(1), ++hashTx, dev::Address())); |
| 132 | + auto result = executeBC(txs, *m_node.chainman); |
| 133 | + BOOST_CHECK(result.first[0].execRes.excepted == dev::eth::TransactionException::None); |
| 134 | +
|
| 135 | + // Check that tstore and tload are bad instructions |
| 136 | + dev::Address proxy = createQtumAddress(txs[0].getHashWith(), txs[0].getNVout()); |
| 137 | + std::vector<QtumTransaction> txCancun; |
| 138 | + txCancun.push_back(createQtumTransaction(getCode(CodeID::setMultiplier_5), 0, GASLIMIT, dev::u256(1), ++hashTx, proxy)); |
| 139 | + txCancun.push_back(createQtumTransaction(getCode(CodeID::multiply_7), 0, GASLIMIT, dev::u256(1), ++hashTx, proxy)); |
| 140 | + result = executeBC(txCancun, *m_node.chainman); |
| 141 | + BOOST_CHECK(result.first[0].execRes.excepted == dev::eth::TransactionException::BadInstruction); |
| 142 | + BOOST_CHECK(result.first[1].execRes.excepted == dev::eth::TransactionException::BadInstruction); |
| 143 | +} |
| 144 | +
|
| 145 | +BOOST_AUTO_TEST_SUITE_END() |
| 146 | +
|
| 147 | +} |
0 commit comments