forked from bcosorg/bcos
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathClient.h
367 lines (288 loc) · 14.4 KB
/
Client.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file Client.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#pragma once
#include <thread>
#include <condition_variable>
#include <mutex>
#include <list>
#include <queue>
#include <atomic>
#include <string>
#include <array>
#include <libdevcore/Common.h>
#include <libdevcore/CommonIO.h>
#include <libdevcore/Guards.h>
#include <libdevcore/Worker.h>
#include <libdevcore/easylog.h>
#include <libethcore/SealEngine.h>
#include <libethcore/ABI.h>
#include <libp2p/Common.h>
#include "BlockChain.h"
#include "Block.h"
#include "CommonNet.h"
#include "ClientBase.h"
#include "SystemContractApi.h"
namespace dev
{
namespace eth
{
class Client;
class DownloadMan;
class SystemContractApi;
enum ClientWorkState
{
Active = 0,
Deleting,
Deleted
};
struct ClientNote: public LogChannel { static const char* name(); static const int verbosity = 2; };
struct ClientChat: public LogChannel { static const char* name(); static const int verbosity = 4; };
struct ClientTrace: public LogChannel { static const char* name(); static const int verbosity = 7; };
struct ClientDetail: public LogChannel { static const char* name(); static const int verbosity = 14; };
struct ActivityReport
{
unsigned ticks = 0;
std::chrono::system_clock::time_point since = std::chrono::system_clock::now();
};
std::ostream& operator<<(std::ostream& _out, ActivityReport const& _r);
/**
* @brief Main API hub for interfacing with Ethereum.
*/
class Client: public ClientBase, protected Worker
{
public:
Client(
ChainParams const& _params,
int _networkID,
p2p::Host* _host,
std::shared_ptr<GasPricer> _gpForAdoption,
std::string const& _dbPath = std::string(),
WithExisting _forceAction = WithExisting::Trust,
TransactionQueue::Limits const& _l = TransactionQueue::Limits {1024, 1024}
);
/// Destructor.
virtual ~Client();
/// Get information on this chain.
ChainParams const& chainParams() const { return bc().chainParams(); }
/// Resets the gas pricer to some other object.
void setGasPricer(std::shared_ptr<GasPricer> _gp) { m_gp = _gp; }
std::shared_ptr<GasPricer> gasPricer() const { return m_gp; }
/// Blocks until all pending transactions have been processed.
virtual void flushTransactions() override;
/// Queues a block for import.
ImportResult queueBlock(bytes const& _block, bool _isSafe = false);
using Interface::call; // to remove warning about hiding virtual function
/// Makes the given call. Nothing is recorded into the state. This cheats by creating a null address and endowing it with a lot of ETH.
ExecutionResult call(Address _dest, bytes const& _data = bytes(), u256 _gas = 125000, u256 _value = 0, u256 _gasPrice = 1 * ether, Address const& _from = Address());
/// Get the remaining gas limit in this block.
virtual u256 gasLimitRemaining() const override { return m_postSeal.gasLimitRemaining(); }
/// Get the gas bid price
virtual u256 gasBidPrice() const override { return m_gp->bid(); }
// [PRIVATE API - only relevant for base clients, not available in general]
/// Get the block.
dev::eth::Block block(h256 const& _blockHash, PopulationStatistics* o_stats) const;
/// Get the state of the given block part way through execution, immediately before transaction
/// index @a _txi.
dev::eth::State state(unsigned _txi, h256 const& _block) const;
/// Get the state of the currently pending block part way through execution, immediately before
/// transaction index @a _txi.
dev::eth::State state(unsigned _txi) const;
/// Get the object representing the current state of Ethereum.
dev::eth::Block postState() const { ReadGuard l(x_postSeal); return m_postSeal; }
/// Get the object representing the current canonical blockchain.
BlockChain const& blockChain() const { return bc(); }
/// Get some information on the block queue.
BlockQueueStatus blockQueueStatus() const { return m_bq.status(); }
/// Get some information on the block syncing.
SyncStatus syncStatus() const override;
/// Get the block queue.
BlockQueue const& blockQueue() const { return m_bq; }
/// Get the block queue.
OverlayDB const& stateDB() const { return m_stateDB; }
/// Get some information on the transaction queue.
TransactionQueue::Status transactionQueueStatus() const { return m_tq.status(); }
TransactionQueue::Limits transactionQueueLimits() const { return m_tq.limits(); }
/// Freeze worker thread and sync some of the block queue.
std::tuple<ImportRoute, bool, unsigned> syncQueue(unsigned _max = 1);
// Sealing stuff:
// Note: "mining"/"miner" is deprecated. Use "sealing"/"sealer".
virtual Address author() const override { ReadGuard l(x_preSeal); return m_preSeal.author(); }
virtual void setAuthor(Address const& _us) override { WriteGuard l(x_preSeal); m_preSeal.setAuthor(_us); }
/// Type of sealers available for this seal engine.
strings sealers() const { return sealEngine()->sealers(); }
/// Current sealer in use.
std::string sealer() const { return sealEngine()->sealer(); }
/// Change sealer.
void setSealer(std::string const& _id) { sealEngine()->setSealer(_id); if (wouldSeal()) startSealing(); }
/// Review option for the sealer.
bytes sealOption(std::string const& _name) const { return sealEngine()->option(_name); }
/// Set option for the sealer.
bool setSealOption(std::string const& _name, bytes const& _value) { auto ret = sealEngine()->setOption(_name, _value); if (wouldSeal()) startSealing(); return ret; }
/// Start sealing.
virtual void startSealing() override;
/// Stop sealing.
virtual void stopSealing() override { m_wouldSeal = false; }
/// Are we sealing now?
bool wouldSeal() const override { return m_wouldSeal; }
/// Are we updating the chain (syncing or importing a new block)?
bool isSyncing() const override;
/// Are we syncing the chain?
bool isMajorSyncing() const override;
/// Gets the network id.
u256 networkId() const override;
/// Sets the network id.
void setNetworkId(u256 const& _n) override;
/// Get the seal engine.
SealEngineFace* sealEngine() const override { return bc().sealEngine(); }
// Debug stuff:
DownloadMan const* downloadMan() const;
/// Clears pending transactions. Just for debug use.
void clearPending();
/// Kills the blockchain. Just for debug use.
void killChain() { reopenChain(WithExisting::Kill); }
/// Reloads the blockchain. Just for debug use.
void reopenChain(ChainParams const& _p, WithExisting _we = WithExisting::Trust);
void reopenChain(WithExisting _we);
/// Retries all blocks with unknown parents.
void retryUnknown() { m_bq.retryAllUnknown(); }
/// Get a report of activity.
ActivityReport activityReport() { ActivityReport ret; std::swap(m_report, ret); return ret; }
/// Set the extra data that goes into sealed blocks.
void setExtraData(bytes const& _extraData) { m_extraData = _extraData; }
/// Rewind to a prior head.
void rewind(unsigned _n);
/// Rescue the chain.
void rescue() { bc().rescue(m_stateDB); }
/// Queues a function to be executed in the main thread (that owns the blockchain, etc).
void executeInMainThread(std::function<void()> const& _function);
virtual Block block(h256 const& _block) const override;
using ClientBase::block;
u256 filterCheck(const Transaction & _t, FilterCheckScene _checkscene = FilterCheckScene::None) const override;
void updateSystemContract(std::shared_ptr<Block> block) override;
void updateCache(Address address) override;
virtual bool isMining() const { return m_wouldSeal; }
bool checkWorking(){return isWorking();};
p2p::Host* host();
//get the result from state query result
int getResultInt(ExecutionResult& result, int& value);
//find the contract address by name
Address findContract(const string& contract);
protected:
/// Perform critical setup functions.
/// Must be called in the constructor of the finally derived class.
void init(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId);
/// InterfaceStub methods
BlockChain& bc() override { return m_bc; }
BlockChain const& bc() const override { return m_bc; }
/// Returns the state object for the full block (i.e. the terminal state) for index _h.
/// Works properly with LatestBlock and PendingBlock.
virtual Block preSeal() const override { ReadGuard l(x_preSeal); return m_preSeal; }
virtual Block postSeal() const override { ReadGuard l(x_postSeal); return m_postSeal; }
virtual void prepareForTransaction() override;
/// Collate the changed filters for the bloom filter of the given pending transaction.
/// Insert any filters that are activated into @a o_changed.
void appendFromNewPending(TransactionReceipt const& _receipt, h256Hash& io_changed, h256 _sha3);
/// Collate the changed filters for the hash of the given block.
/// Insert any filters that are activated into @a o_changed.
void appendFromBlock(h256 const& _blockHash, BlockPolarity _polarity, h256Hash& io_changed);
/// Record that the set of filters @a _filters have changed.
/// This doesn't actually make any callbacks, but incrememnts some counters in m_watches.
void noteChanged(h256Hash const& _filters);
/// Submit
virtual bool submitSealed(bytes const& _s);
protected:
/// Called when Worker is starting.
void startedWorking() override;
/// Do some work. Handles blockchain maintenance and sealing.
virtual void doWork(bool _doWait);
virtual void doWork() override { doWork(true); }
/// Called when Worker is exiting.
void doneWorking() override;
/// Called when wouldSeal(), pendingTransactions() have changed.
virtual void rejigSealing();
/// Called on chain changes
void onDeadBlocks(h256s const& _blocks, h256Hash& io_changed);
/// Called on chain changes
virtual void onNewBlocks(h256s const& _blocks, h256Hash& io_changed);
/// Called after processing blocks by onChainChanged(_ir)
void resyncStateFromChain();
/// Clear working state of transactions
void resetState();
/// Magically called when the chain has changed. An import route is provided.
/// Called by either submitWork() or in our main thread through syncBlockQueue().
void onChainChanged(ImportRoute const& _ir);
/// Signal handler for when the block queue needs processing.
virtual void syncBlockQueue();
/// Signal handler for when the block queue needs processing.
virtual void syncTransactionQueue();
/// Magically called when m_tq needs syncing. Be nice and don't block.
virtual void onTransactionQueueReady() { m_syncTransactionQueue = true; m_signalled.notify_all(); }
/// Magically called when m_bq needs syncing. Be nice and don't block.
void onBlockQueueReady() { m_syncBlockQueue = true; m_signalled.notify_all(); }
/// Called when the post state has changed (i.e. when more transactions are in it or we're sealing on a new block).
/// This updates m_sealingInfo.
void onPostStateChanged();
/// Does garbage collection on watches.
void checkWatchGarbage();
/// Ticks various system-level objects.
void tick();
/// Called when we have attempted to import a bad block.
/// @warning May be called from any thread.
void onBadBlock(Exception& _ex) const;
/// Executes the pending functions in m_functionQueue
void callQueuedFunctions();
void updateConfig();
BlockChain m_bc; ///< Maintains block database and owns the seal engine.
BlockQueue m_bq; ///< Maintains a list of incoming blocks not yet on the blockchain (to be imported).
std::shared_ptr<GasPricer> m_gp; ///< The gas pricer.
OverlayDB m_stateDB; ///< Acts as the central point for the state database, so multiple States can share it.
mutable SharedMutex x_preSeal; ///< Lock on m_preSeal.
Block m_preSeal; ///< The present state of the client.
mutable SharedMutex x_postSeal; ///< Lock on m_postSeal.
Block m_postSeal; ///< The state of the client which we're sealing (i.e. it'll have all the rewards added).
mutable SharedMutex x_working; ///< Lock on m_working.
Block m_working; ///< The state of the client which we're sealing (i.e. it'll have all the rewards added), while we're actually working on it.
BlockHeader m_sealingInfo; ///< The header we're attempting to seal on (derived from m_postSeal).
bool remoteActive() const; ///< Is there an active and valid remote worker?
bool m_remoteWorking = false; ///< Has the remote worker recently been reset?
std::atomic<bool> m_needStateReset = { false }; ///< Need reset working state to premin on next sync
std::chrono::system_clock::time_point m_lastGetWork; ///< Is there an active and valid remote worker?
std::weak_ptr<EthereumHost> m_host; ///< Our Ethereum Host. Don't do anything if we can't lock.
Handler<> m_tqReady;
Handler<h256 const&> m_tqReplaced;
Handler<> m_bqReady;
bool m_wouldSeal = false; ///< True if we /should/ be sealing.
bool m_wouldButShouldnot = false; ///< True if the last time we called rejigSealing wouldSeal() was true but sealer's shouldSeal() was false.
mutable std::chrono::system_clock::time_point m_lastGarbageCollection;
///< When did we last both doing GC on the watches?
mutable std::chrono::system_clock::time_point m_lastTick = std::chrono::system_clock::now();
///< When did we last tick()?
unsigned m_syncAmount = 50; ///< Number of blocks to sync in each go.
ActivityReport m_report;
SharedMutex x_functionQueue;
std::queue<std::function<void()>> m_functionQueue; ///< Functions waiting to be executed in the main thread.
std::condition_variable m_signalled;
Mutex x_signalled;
std::atomic<bool> m_syncTransactionQueue = {false};
std::atomic<bool> m_syncBlockQueue = {false};
bytes m_extraData;
u256 m_maxBlockTranscations = 1000;
std::shared_ptr<SystemContractApi> m_systemcontractapi;
};
}
}