1 #pragma once
2 
3 #include <libdevcore/UndefMacros.h>
4 #include <libethereum/State.h>
5 #include <libevm/ExtVMFace.h>
6 #include <crypto/sha256.h>
7 #include <crypto/ripemd160.h>
8 #include <uint256.h>
9 #include <util/convert.h>
10 #include <primitives/transaction.h>
11 #include <qtum/qtumtransaction.h>
12 
13 #include <libethereum/Executive.h>
14 #include <libethcore/SealEngine.h>
15 
16 using OnOpFunc = std::function<void(uint64_t, uint64_t, dev::eth::Instruction, dev::bigint, dev::bigint,
17     dev::bigint, dev::eth::VMFace const*, dev::eth::ExtVMFace const*)>;
18 using plusAndMinus = std::pair<dev::u256, dev::u256>;
19 using valtype = std::vector<unsigned char>;
20 
21 struct TransferInfo{
22     dev::Address from;
23     dev::Address to;
24     dev::u256 value;
25 };
26 
27 struct Vin{
28     dev::h256 hash;
29     uint32_t nVout;
30     dev::u256 value;
31     uint8_t alive;
32 };
33 
34 class QtumTransactionReceipt: public dev::eth::TransactionReceipt {
35 public:
QtumTransactionReceipt(dev::h256 const & state_root,dev::h256 const & utxo_root,dev::u256 const & gas_used,dev::eth::LogEntries const & log)36     QtumTransactionReceipt(dev::h256 const& state_root, dev::h256 const& utxo_root, dev::u256 const& gas_used, dev::eth::LogEntries const& log) : dev::eth::TransactionReceipt(state_root, gas_used, log), m_utxoRoot(utxo_root) {}
37 
utxoRoot()38     dev::h256 const& utxoRoot() const {
39         return m_utxoRoot;
40     }
41 private:
42     dev::h256 m_utxoRoot;
43 };
44 
45 struct ResultExecute{
46     dev::eth::ExecutionResult execRes;
47     QtumTransactionReceipt txRec;
48     CTransaction tx;
49 };
50 
51 namespace qtum{
52     template <class DB>
commit(std::unordered_map<dev::Address,Vin> const & _cache,dev::eth::SecureTrieDB<dev::Address,DB> & _state,std::unordered_map<dev::Address,dev::eth::Account> const & _cacheAcc)53     dev::AddressHash commit(std::unordered_map<dev::Address, Vin> const& _cache, dev::eth::SecureTrieDB<dev::Address, DB>& _state, std::unordered_map<dev::Address, dev::eth::Account> const& _cacheAcc)
54     {
55         dev::AddressHash ret;
56         for (auto const& i: _cache){
57             if(i.second.alive == 0){
58                  _state.remove(i.first);
59             } else {
60                 dev::RLPStream s(4);
61                 s << i.second.hash << i.second.nVout << i.second.value << i.second.alive;
62                 _state.insert(i.first, &s.out());
63             }
64             ret.insert(i.first);
65         }
66         return ret;
67     }
68 }
69 
70 class CondensingTX;
71 
72 class QtumState : public dev::eth::State {
73 
74 public:
75 
76     QtumState();
77 
78     QtumState(dev::u256 const& _accountStartNonce, dev::OverlayDB const& _db, const std::string& _path, dev::eth::BaseState _bs = dev::eth::BaseState::PreExisting);
79 
80     ResultExecute execute(dev::eth::EnvInfo const& _envInfo, dev::eth::SealEngineFace const& _sealEngine, QtumTransaction const& _t, dev::eth::Permanence _p = dev::eth::Permanence::Committed, dev::eth::OnOpFunc const& _onOp = OnOpFunc());
81 
setRootUTXO(dev::h256 const & _r)82     void setRootUTXO(dev::h256 const& _r) { cacheUTXO.clear(); stateUTXO.setRoot(_r); }
83 
setCacheUTXO(dev::Address const & address,Vin const & vin)84     void setCacheUTXO(dev::Address const& address, Vin const& vin) { cacheUTXO.insert(std::make_pair(address, vin)); }
85 
rootHashUTXO()86     dev::h256 rootHashUTXO() const { return stateUTXO.root(); }
87 
88     std::unordered_map<dev::Address, Vin> vins() const; // temp
89 
dbUtxo()90     dev::OverlayDB const& dbUtxo() const { return dbUTXO; }
91 
dbUtxo()92     dev::OverlayDB& dbUtxo() { return dbUTXO; }
93 
createQtumAddress(dev::h256 hashTx,uint32_t voutNumber)94     static const dev::Address createQtumAddress(dev::h256 hashTx, uint32_t voutNumber){
95         uint256 hashTXid(h256Touint(hashTx));
96         std::vector<unsigned char> txIdAndVout(hashTXid.begin(), hashTXid.end());
97         std::vector<unsigned char> voutNumberChrs;
98         if (voutNumberChrs.size() < sizeof(voutNumber))voutNumberChrs.resize(sizeof(voutNumber));
99         std::memcpy(voutNumberChrs.data(), &voutNumber, sizeof(voutNumber));
100         txIdAndVout.insert(txIdAndVout.end(),voutNumberChrs.begin(),voutNumberChrs.end());
101 
102         std::vector<unsigned char> SHA256TxVout(32);
103         CSHA256().Write(txIdAndVout.data(), txIdAndVout.size()).Finalize(SHA256TxVout.data());
104 
105         std::vector<unsigned char> hashTxIdAndVout(20);
106         CRIPEMD160().Write(SHA256TxVout.data(), SHA256TxVout.size()).Finalize(hashTxIdAndVout.data());
107 
108         return dev::Address(hashTxIdAndVout);
109     }
110 
111     void deployDelegationsContract();
112 
~QtumState()113     virtual ~QtumState(){}
114 
115     friend CondensingTX;
116 
117 private:
118 
119     void transferBalance(dev::Address const& _from, dev::Address const& _to, dev::u256 const& _value);
120 
121     Vin const* vin(dev::Address const& _a) const;
122 
123     Vin* vin(dev::Address const& _addr);
124 
125     // void commit(CommitBehaviour _commitBehaviour);
126 
127     void kill(dev::Address _addr);
128 
129     void addBalance(dev::Address const& _id, dev::u256 const& _amount);
130 
131     void deleteAccounts(std::set<dev::Address>& addrs);
132 
133     void updateUTXO(const std::unordered_map<dev::Address, Vin>& vins);
134 
135     void printfErrorLog(const dev::eth::TransactionException er);
136 
137     dev::Address newAddress;
138 
139     std::vector<TransferInfo> transfers;
140 
141     dev::OverlayDB dbUTXO;
142 
143 	dev::eth::SecureTrieDB<dev::Address, dev::OverlayDB> stateUTXO;
144 
145 	std::unordered_map<dev::Address, Vin> cacheUTXO;
146 
147 	void validateTransfersWithChangeLog();
148 };
149 
150 
151 struct TemporaryState{
152     std::unique_ptr<QtumState>& globalStateRef;
153     dev::h256 oldHashStateRoot;
154     dev::h256 oldHashUTXORoot;
155 
TemporaryStateTemporaryState156     TemporaryState(std::unique_ptr<QtumState>& _globalStateRef) :
157         globalStateRef(_globalStateRef),
158         oldHashStateRoot(globalStateRef->rootHash()),
159         oldHashUTXORoot(globalStateRef->rootHashUTXO()) {}
160 
SetRootTemporaryState161     void SetRoot(dev::h256 newHashStateRoot, dev::h256 newHashUTXORoot)
162     {
163         globalStateRef->setRoot(newHashStateRoot);
164         globalStateRef->setRootUTXO(newHashUTXORoot);
165     }
166 
~TemporaryStateTemporaryState167     ~TemporaryState(){
168         globalStateRef->setRoot(oldHashStateRoot);
169         globalStateRef->setRootUTXO(oldHashUTXORoot);
170     }
171     TemporaryState() = delete;
172     TemporaryState(const TemporaryState&) = delete;
173     TemporaryState& operator=(const TemporaryState&) = delete;
174     TemporaryState(TemporaryState&&) = delete;
175     TemporaryState& operator=(TemporaryState&&) = delete;
176 };
177 
178 
179 ///////////////////////////////////////////////////////////////////////////////////////////
180 class CondensingTX{
181 
182 public:
183 
transfers(_transfers)184     CondensingTX(QtumState* _state, const std::vector<TransferInfo>& _transfers, const QtumTransaction& _transaction, std::set<dev::Address> _deleteAddresses = std::set<dev::Address>()) : transfers(_transfers), deleteAddresses(_deleteAddresses), transaction(_transaction), state(_state){}
185 
186     CTransaction createCondensingTX();
187 
188     std::unordered_map<dev::Address, Vin> createVin(const CTransaction& tx);
189 
reachedVoutLimit()190     bool reachedVoutLimit(){ return voutOverflow; }
191 
192 private:
193 
194     void selectionVin();
195 
196     void calculatePlusAndMinus();
197 
198     bool createNewBalances();
199 
200     std::vector<CTxIn> createVins();
201 
202     std::vector<CTxOut> createVout();
203 
204     bool checkDeleteAddress(dev::Address addr);
205 
206     std::map<dev::Address, plusAndMinus> plusMinusInfo;
207 
208     std::map<dev::Address, dev::u256> balances;
209 
210     std::map<dev::Address, uint32_t> nVouts;
211 
212     std::map<dev::Address, Vin> vins;
213 
214     const std::vector<TransferInfo>& transfers;
215 
216     //We don't need the ordered nature of "set" here, but unordered_set's theoretical worst complexity is O(n), whereas set is O(log n)
217     //So, making this unordered_set could be an attack vector
218     const std::set<dev::Address> deleteAddresses;
219 
220     const QtumTransaction& transaction;
221 
222     QtumState* state;
223 
224     bool voutOverflow = false;
225 
226 };
227 ///////////////////////////////////////////////////////////////////////////////////////////
228