1 #include <boost/test/unit_test.hpp>
2 #include <qtumtests/test_utils.h>
3 #include <script/standard.h>
4 #include <chainparams.h>
5 
6 namespace BtcEcrecoverTest{
7 
8 const dev::u256 GASLIMIT = dev::u256(500000);
9 const dev::h256 HASHTX = dev::h256(ParseHex("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"));
10 
11 // Contract for btc_ecrecover check
12 const std::vector<valtype> CODE = {
13     /*
14     pragma solidity ^0.4.0;
15     library Crypto
16     {
17         function btc_ecrecover(bytes32 msgh, uint8 v, bytes32 r, bytes32 s) public view returns(bytes addr)
18         {
19             uint256[4] memory input;
20             input[0] = uint256(msgh);
21             input[1] = v;
22             input[2] = uint256(r);
23             input[3] = uint256(s);
24 
25             uint256[2] memory p;
26             assembly
27             {
28                 if iszero(call(not(0), 0x85, 0, input, 0x80, p, 0x40))
29                 {
30                     revert(0, 0)
31                 }
32             }
33             addr = toBytes(p[0]);
34         }
35 
36         function toBytes(uint256 x) internal pure returns (bytes b)
37         {
38             b = new bytes(32);
39             assembly { mstore(add(b, 32), x) }
40         }
41     }
42     */
43     // Contract that call btc_ecrecover
44     valtype(ParseHex("61029e610030600b82828239805160001a6073146000811461002057610022565bfe5b5030600052607381538281f3007300000000000000000000000000000000000000003014608060405260043610610058576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806369bc09631461005d575b600080fd5b6100a86004803603810190808035600019169060200190929190803560ff16906020019092919080356000191690602001909291908035600019169060200190929190505050610123565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100e85780820151818401526020810190506100cd565b50505050905090810190601f1680156101155780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b606061012d61022d565b610135610250565b866001900482600060048110151561014957fe5b6020020181815250508560ff1682600160048110151561016557fe5b602002018181525050846001900482600260048110151561018257fe5b602002018181525050836001900482600360048110151561019f57fe5b60200201818152505060408160808460006085600019f115156101c157600080fd5b6101dd8160006002811015156101d357fe5b60200201516101e9565b92505050949350505050565b606060206040519080825280601f01601f19166020018201604052801561021f5781602001602082028038833980820191505090505b509050816020820152919050565b608060405190810160405280600490602082028038833980820191505090505090565b60408051908101604052806002906020820280388339808201915050905050905600a165627a7a723058202c030fcf0261d136398030f4a0109ecc4c041333bf65bcbd4995b2f8332926890029")),
45 
46     // btc_ecrecover(bytes32 msgh, uint8 v, bytes32 r, bytes32 s) v=27
47     valtype(ParseHex("69bc09631476abb745d423bf09273f1afd887d951181d25adc66c4834a70491911b7f750000000000000000000000000000000000000000000000000000000000000001be6ca9bba58c88611fad66a6ce8f996908195593807c4b38bd528d2cff09d4eb33e5bfbbf4d3e39b1a2fd816a7680c19ebebaf3a141b239934ad43cb33fcec8ce")),
48 
49     // btc_ecrecover(bytes32 msgh, uint8 v, bytes32 r, bytes32 s) v=28
50     valtype(ParseHex("69bc09631476abb745d423bf09273f1afd887d951181d25adc66c4834a70491911b7f750000000000000000000000000000000000000000000000000000000000000001ce6ca9bba58c88611fad66a6ce8f996908195593807c4b38bd528d2cff09d4eb33e5bfbbf4d3e39b1a2fd816a7680c19ebebaf3a141b239934ad43cb33fcec8ce")),
51 
52     // btc_ecrecover(bytes32 msgh, uint8 v, bytes32 r, bytes32 s) v=31
53     valtype(ParseHex("69bc09631476abb745d423bf09273f1afd887d951181d25adc66c4834a70491911b7f750000000000000000000000000000000000000000000000000000000000000001fe6ca9bba58c88611fad66a6ce8f996908195593807c4b38bd528d2cff09d4eb33e5bfbbf4d3e39b1a2fd816a7680c19ebebaf3a141b239934ad43cb33fcec8ce")),
54 
55     // btc_ecrecover(bytes32 msgh, uint8 v, bytes32 r, bytes32 s) v=32
56     valtype(ParseHex("69bc09631476abb745d423bf09273f1afd887d951181d25adc66c4834a70491911b7f7500000000000000000000000000000000000000000000000000000000000000020e6ca9bba58c88611fad66a6ce8f996908195593807c4b38bd528d2cff09d4eb33e5bfbbf4d3e39b1a2fd816a7680c19ebebaf3a141b239934ad43cb33fcec8ce")),
57 
58     // Valid address result v=27
59     valtype(ParseHex("00000000000000000000000011f50cfcb40d4e0bcdb4c728664d26bd969c8661")),
60 
61     // Valid address result v=28
62     valtype(ParseHex("0000000000000000000000005b0bf163d8d62090d634bc5c20bb47602cc686fe")),
63 
64     // Valid address result v=31
65     valtype(ParseHex("000000000000000000000000931c1f36709cd3aa8623a38db7a905d31ddf97e3")),
66 
67     // Valid address result v=32
68     valtype(ParseHex("000000000000000000000000575e154116a125cee7053db093d94c6fb522144f")),
69 
70     // Not valid address result
71     valtype(ParseHex("0000000000000000000000000000000000000000000000000000000000000000"))
72 };
73 
parseOutput(const dev::bytes & output)74 dev::bytes parseOutput(const dev::bytes& output)
75 {
76     return dev::bytes(output.begin() + 64, output.end());
77 }
78 
genesisLoading()79 void genesisLoading(){
80     const CChainParams& chainparams = Params();
81     dev::eth::ChainParams cp(chainparams.EVMGenesisInfo());
82     globalState->populateFrom(cp.genesisState);
83     globalSealEngine = std::unique_ptr<dev::eth::SealEngineFace>(cp.createSealEngine());
84     globalState->db().commit();
85 }
86 
createNewBlocks(TestChain100Setup * testChain100Setup,size_t n)87 void createNewBlocks(TestChain100Setup* testChain100Setup, size_t n){
88     std::function<void(size_t n)> generateBlocks = [&](size_t n){
89         dev::h256 oldHashStateRoot = globalState->rootHash();
90         dev::h256 oldHashUTXORoot = globalState->rootHashUTXO();
91         for(size_t i = 0; i < n; i++){
92             testChain100Setup->CreateAndProcessBlock({}, GetScriptForRawPubKey(testChain100Setup->coinbaseKey.GetPubKey()));
93         }
94         globalState->setRoot(oldHashStateRoot);
95         globalState->setRootUTXO(oldHashUTXORoot);
96     };
97 
98     generateBlocks(n);
99 }
BOOST_FIXTURE_TEST_SUITE(btcecrecoverfork_tests,TestChain100Setup)100 BOOST_FIXTURE_TEST_SUITE(btcecrecoverfork_tests, TestChain100Setup)
101 
102 BOOST_AUTO_TEST_CASE(checking_btcecrecover_after_fork){
103     // Initialize
104 //    initState();
105     genesisLoading();
106     createNewBlocks(this, 499);
107     dev::h256 hashTx(HASHTX);
108 
109     // Create contract
110     std::vector<QtumTransaction> txs;
111     txs.push_back(createQtumTransaction(CODE[0], 0, GASLIMIT, dev::u256(1), hashTx, dev::Address()));
112     executeBC(txs);
113 
114     // Call btc_ecrecover
115     dev::Address proxy = createQtumAddress(txs[0].getHashWith(), txs[0].getNVout());
116     std::vector<QtumTransaction> txBtcEcrecover;
117     txBtcEcrecover.push_back(createQtumTransaction(CODE[1], 0, GASLIMIT, dev::u256(1), ++hashTx, proxy));
118     txBtcEcrecover.push_back(createQtumTransaction(CODE[2], 0, GASLIMIT, dev::u256(1), ++hashTx, proxy));
119     txBtcEcrecover.push_back(createQtumTransaction(CODE[3], 0, GASLIMIT, dev::u256(1), ++hashTx, proxy));
120     txBtcEcrecover.push_back(createQtumTransaction(CODE[4], 0, GASLIMIT, dev::u256(1), ++hashTx, proxy));
121 
122     // Execute contracts
123     auto result = executeBC(txBtcEcrecover);
124 
125     // Check results
126     dev::bytes output = parseOutput(result.first[0].execRes.output);
127     BOOST_CHECK(dev::h256(output) == dev::h256(CODE[5]));
128     output = parseOutput(result.first[1].execRes.output);
129     BOOST_CHECK(dev::h256(output) == dev::h256(CODE[6]));
130     output = parseOutput(result.first[2].execRes.output);
131     BOOST_CHECK(dev::h256(output) == dev::h256(CODE[7]));
132     output = parseOutput(result.first[3].execRes.output);
133     BOOST_CHECK(dev::h256(output) == dev::h256(CODE[8]));
134 }
135 
BOOST_AUTO_TEST_CASE(checking_btcecrecover_before_fork)136 BOOST_AUTO_TEST_CASE(checking_btcecrecover_before_fork){
137     // Initialize
138 //    initState();
139     genesisLoading();
140     createNewBlocks(this, 498);
141     dev::h256 hashTx(HASHTX);
142 
143     // Create contract
144     std::vector<QtumTransaction> txs;
145     txs.push_back(createQtumTransaction(CODE[0], 0, GASLIMIT, dev::u256(1), hashTx, dev::Address()));
146     executeBC(txs);
147 
148     // Call btc_ecrecover
149     dev::Address proxy = createQtumAddress(txs[0].getHashWith(), txs[0].getNVout());
150     std::vector<QtumTransaction> txBtcEcrecover;
151     txBtcEcrecover.push_back(createQtumTransaction(CODE[1], 0, GASLIMIT, dev::u256(1), ++hashTx, proxy));
152     txBtcEcrecover.push_back(createQtumTransaction(CODE[2], 0, GASLIMIT, dev::u256(1), ++hashTx, proxy));
153     txBtcEcrecover.push_back(createQtumTransaction(CODE[3], 0, GASLIMIT, dev::u256(1), ++hashTx, proxy));
154     txBtcEcrecover.push_back(createQtumTransaction(CODE[4], 0, GASLIMIT, dev::u256(1), ++hashTx, proxy));
155 
156      // Execute contracts
157     auto result = executeBC(txBtcEcrecover);
158 
159     // Check results
160     dev::bytes output = parseOutput(result.first[0].execRes.output);
161     BOOST_CHECK(dev::h256(output) == dev::h256(CODE[9]));
162     output = parseOutput(result.first[1].execRes.output);
163     BOOST_CHECK(dev::h256(output) == dev::h256(CODE[9]));
164     output = parseOutput(result.first[2].execRes.output);
165     BOOST_CHECK(dev::h256(output) == dev::h256(CODE[9]));
166     output = parseOutput(result.first[3].execRes.output);
167     BOOST_CHECK(dev::h256(output) == dev::h256(CODE[9]));
168 }
169 
170 BOOST_AUTO_TEST_SUITE_END()
171 
172 }
173