) Gets or sets verbosity level." << endl
+ << " setetherprice Resets the ether price." << endl
+ << " setpriority
Resets the transaction priority." << endl
+ << " minestart Starts mining." << endl
<< " minestart Starts mining." << endl
<< " minestop Stops mining." << endl
<< " mineforce Forces mining, even when there are no transactions." << endl
@@ -85,12 +88,12 @@ void interactiveHelp()
<< " send Execute a given transaction with current secret." << endl
<< " contract Create a new contract with current secret." << endl
<< " peers List the peers that are connected" << endl
- << " listAccounts List the accounts on the network." << endl
- << " listContracts List the contracts on the network." << endl
- << " setSecret Set the secret to the hex secret key." < Set the coinbase (mining payout) address." < Export the config (.RLP) to the path provided." < Import the config (.RLP) from the path provided." < Set the secret to the hex secret key." < Set the coinbase (mining payout) address." < Export the config (.RLP) to the path provided." < Import the config (.RLP) from the path provided." < Dumps a contract to /.evm." << endl
<< " dumptrace Dumps a transaction trace" << endl << "to . should be one of pretty, standard, standard+." << endl
<< " dumpreceipt Dumps a transation receipt." << endl
@@ -104,9 +107,11 @@ void help()
<< "Options:" << endl
<< " -a,--address Set the coinbase (mining payout) address to addr (default: auto)." << endl
<< " -b,--bootstrap Connect to the default Ethereum peerserver." << endl
+ << " -B,--block-fees Set the block fee profit in the reference unit e.g. ¢ (Default: 15)." << endl
<< " -c,--client-name Add a name to your client's version string (default: blank)." << endl
<< " -d,--db-path Load database from path (default: ~/.ethereum " << endl
<< " /Etherum or Library/Application Support/Ethereum)." << endl
+ << " -e,--ether-price Set the ether price in the reference unit e.g. ¢ (Default: 30.679)." << endl
<< " -f,--force-mining Mine even when there are no transaction to mine (Default: off)" << endl
<< " -h,--help Show this help message and exit." << endl
<< " -i,--interactive Enter interactive mode (default: non-interactive)." << endl
@@ -115,11 +120,12 @@ void help()
<< " --json-rpc-port Specify JSON-RPC server port (implies '-j', default: 8080)." << endl
#endif
<< " -l,--listen Listen on the given port for incoming connected (default: 30303)." << endl
+ << " -L,--local-networking Use peers whose addresses are local." << endl
<< " -m,--mining Enable mining, optionally for a specified number of blocks (Default: off)" << endl
<< " -n,--upnp Use upnp for NAT (default: on)." << endl
- << " -L,--local-networking Use peers whose addresses are local." << endl
<< " -o,--mode Start a full node or a peer node (Default: full)." << endl
<< " -p,--port Connect to remote port (default: 30303)." << endl
+ << " -P,--priority <0 - 100> Default % priority of a transaction (default: 50)." << endl
<< " -r,--remote Connect to remote host (default: none)." << endl
<< " -s,--secret Set the secret key for use with send command (default: auto)." << endl
<< " -t,--miners Number of mining threads to start (Default: " << thread::hardware_concurrency() << ")" << endl
@@ -128,7 +134,7 @@ void help()
<< " -x,--peers Attempt to connect to given number of peers (Default: 5)." << endl
<< " -V,--version Show the version and exit." << endl
#if ETH_EVMJIT
- << " --jit Use EVM JIT (default: off)." << endl
+ << " --jit Use EVM JIT (default: off)." << endl
#endif
;
exit(0);
@@ -212,6 +218,9 @@ int main(int argc, char** argv)
bool structuredLogging = false;
string structuredLoggingFormat = "%Y-%m-%dT%H:%M:%S";
string clientName;
+ TransactionPriority priority = TransactionPriority::Medium;
+ double etherPrice = 30.679;
+ double blockFees = 15.0;
// Init defaults
Defaults::get();
@@ -289,6 +298,48 @@ int main(int argc, char** argv)
structuredLogging = true;
else if ((arg == "-d" || arg == "--path" || arg == "--db-path") && i + 1 < argc)
dbPath = argv[++i];
+ else if ((arg == "-B" || arg == "--block-fees") && i + 1 < argc)
+ {
+ try {
+ blockFees = stof(argv[++i]);
+ }
+ catch (...) {
+ cerr << "Bad " << arg << " option: " << argv[++i] << endl;
+ return -1;
+ }
+ }
+ else if ((arg == "-e" || arg == "--ether-price") && i + 1 < argc)
+ {
+ try {
+ etherPrice = stof(argv[++i]);
+ }
+ catch (...) {
+ cerr << "Bad " << arg << " option: " << argv[++i] << endl;
+ return -1;
+ }
+ }
+ else if ((arg == "-P" || arg == "--priority") && i + 1 < argc)
+ {
+ string m = boost::to_lower_copy(string(argv[++i]));
+ if (m == "lowest")
+ priority = TransactionPriority::Lowest;
+ else if (m == "low")
+ priority = TransactionPriority::Low;
+ else if (m == "medium" || m == "mid" || m == "default" || m == "normal")
+ priority = TransactionPriority::Medium;
+ else if (m == "high")
+ priority = TransactionPriority::High;
+ else if (m == "highest")
+ priority = TransactionPriority::Highest;
+ else
+ try {
+ priority = (TransactionPriority)(max(0, min(100, stoi(m))) * 8 / 100);
+ }
+ catch (...) {
+ cerr << "Unknown " << arg << " option: " << m << endl;
+ return -1;
+ }
+ }
else if ((arg == "-m" || arg == "--mining") && i + 1 < argc)
{
string m = argv[++i];
@@ -301,7 +352,7 @@ int main(int argc, char** argv)
mining = stoi(m);
}
catch (...) {
- cerr << "Unknown -m/--mining option: " << m << endl;
+ cerr << "Unknown " << arg << " option: " << m << endl;
return -1;
}
}
@@ -373,10 +424,12 @@ int main(int argc, char** argv)
miners
);
web3.setIdealPeerCount(peers);
+ std::shared_ptr gasPricer = make_shared(u256(double(ether / 1000) / etherPrice), u256(blockFees * 1000));
eth::Client* c = mode == NodeMode::Full ? web3.ethereum() : nullptr;
StructuredLogger::starting(clientImplString, dev::Version);
if (c)
{
+ c->setGasPricer(gasPricer);
c->setForceMining(forceMining);
c->setAddress(coinbase);
}
@@ -435,6 +488,7 @@ int main(int argc, char** argv)
istringstream iss(l);
string cmd;
iss >> cmd;
+ boost::to_lower(cmd);
if (cmd == "netstart")
{
iss >> netPrefs.listenPort;
@@ -466,6 +520,42 @@ int main(int argc, char** argv)
iss >> enable;
c->setForceMining(isTrue(enable));
}
+ else if (c && cmd == "setblockfees")
+ {
+ iss >> blockFees;
+ gasPricer->setRefBlockFees(u256(blockFees * 1000));
+ cout << "Block fees: " << blockFees << endl;
+ }
+ else if (c && cmd == "setetherprice")
+ {
+ iss >> etherPrice;
+ gasPricer->setRefPrice(u256(double(ether / 1000) / etherPrice));
+ cout << "ether Price: " << etherPrice << endl;
+ }
+ else if (c && cmd == "setpriority")
+ {
+ string m;
+ iss >> m;
+ boost::to_lower(m);
+ if (m == "lowest")
+ priority = TransactionPriority::Lowest;
+ else if (m == "low")
+ priority = TransactionPriority::Low;
+ else if (m == "medium" || m == "mid" || m == "default" || m == "normal")
+ priority = TransactionPriority::Medium;
+ else if (m == "high")
+ priority = TransactionPriority::High;
+ else if (m == "highest")
+ priority = TransactionPriority::Highest;
+ else
+ try {
+ priority = (TransactionPriority)(max(0, min(100, stoi(m))) * 8 / 100);
+ }
+ catch (...) {
+ cerr << "Unknown priority: " << m << endl;
+ }
+ cout << "Priority: " << (int)priority << "/8" << endl;
+ }
else if (cmd == "verbosity")
{
if (iss.peek() != -1)
@@ -536,6 +626,9 @@ int main(int argc, char** argv)
iss >> hexAddr >> amount >> gasPrice >> gas >> sechex >> sdata;
+ if (!gasPrice)
+ gasPrice = gasPricer->bid(priority);
+
cnote << "Data:";
cnote << sdata;
bytes data = dev::eth::parseData(sdata);
@@ -582,7 +675,7 @@ int main(int argc, char** argv)
else
cwarn << "Require parameters: transact ADDRESS AMOUNT GASPRICE GAS SECRET DATA";
}
- else if (c && cmd == "listContracts")
+ else if (c && cmd == "listcontracts")
{
auto acs =c->addresses();
string ss;
@@ -593,7 +686,7 @@ int main(int argc, char** argv)
cout << ss << endl;
}
}
- else if (c && cmd == "listAccounts")
+ else if (c && cmd == "listaccounts")
{
auto acs =c->addresses();
string ss;
@@ -809,7 +902,7 @@ int main(int argc, char** argv)
}
}
}
- else if (cmd == "setSecret")
+ else if (cmd == "setsecret")
{
if (iss.peek() != -1)
{
@@ -820,7 +913,7 @@ int main(int argc, char** argv)
else
cwarn << "Require parameter: setSecret HEXSECRETKEY";
}
- else if (cmd == "setAddress")
+ else if (cmd == "setaddress")
{
if (iss.peek() != -1)
{
@@ -848,7 +941,7 @@ int main(int argc, char** argv)
else
cwarn << "Require parameter: setAddress HEXADDRESS";
}
- else if (cmd == "exportConfig")
+ else if (cmd == "exportconfig")
{
if (iss.peek() != -1)
{
@@ -861,7 +954,7 @@ int main(int argc, char** argv)
else
cwarn << "Require parameter: exportConfig PATH";
}
- else if (cmd == "importConfig")
+ else if (cmd == "importconfig")
{
if (iss.peek() != -1)
{
diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp
index 05e1b86af..4572e29b8 100644
--- a/libethereum/Client.cpp
+++ b/libethereum/Client.cpp
@@ -60,16 +60,58 @@ void VersionChecker::setOk()
}
}
+void BasicGasPricer::update(BlockChain const& _bc)
+{
+ unsigned c = 0;
+ h256 p = _bc.currentHash();
+ m_gasPerBlock = _bc.info(p).gasLimit;
+
+ map dist;
+ unsigned total;
+ while (c < 1000 && p)
+ {
+ BlockInfo bi = _bc.info(p);
+ if (bi.transactionsRoot != EmptyTrie)
+ {
+ auto bb = _bc.block(p);
+ RLP r(bb);
+ BlockReceipts brs(_bc.receipts(bi.hash));
+ for (unsigned i = 0; i < r[1].size(); ++i)
+ {
+ auto gu = brs.receipts[i].gasUsed();
+ dist[Transaction(r[1][i].data(), CheckSignature::None).gasPrice()] += (unsigned)brs.receipts[i].gasUsed();
+ total += (unsigned)gu;
+ }
+ }
+ p = bi.parentHash;
+ ++c;
+ }
+ if (total > 0)
+ {
+ unsigned t = 0;
+ unsigned q = 1;
+ m_octiles[0] = dist.begin()->first;
+ for (auto const& i: dist)
+ {
+ for (; t <= total * q / 8 && t + i.second > total * q / 8; ++q)
+ m_octiles[q] = i.first;
+ if (q > 7)
+ break;
+ }
+ m_octiles[8] = dist.rbegin()->first;
+ }
+}
+
Client::Client(p2p::Host* _extNet, std::string const& _dbPath, bool _forceClean, u256 _networkId, int _miners):
Worker("eth"),
m_vc(_dbPath),
m_bc(_dbPath, !m_vc.ok() || _forceClean),
- m_gp(u256("60000000000000")),
+ m_gp(new TrivialGasPricer),
m_stateDB(State::openDB(_dbPath, !m_vc.ok() || _forceClean)),
m_preMine(Address(), m_stateDB),
m_postMine(Address(), m_stateDB)
{
- m_gp.updateQuartiles(m_bc);
+ m_gp->update(m_bc);
m_host = _extNet->registerCapability(new EthereumHost(m_bc, m_tq, m_bq, _networkId));
@@ -85,16 +127,16 @@ Client::Client(p2p::Host* _extNet, std::string const& _dbPath, bool _forceClean,
startWorking();
}
-Client::Client(p2p::Host* _extNet, u256 weiPerCent, std::string const& _dbPath, bool _forceClean, u256 _networkId, int _miners):
+Client::Client(p2p::Host* _extNet, std::shared_ptr _gp, std::string const& _dbPath, bool _forceClean, u256 _networkId, int _miners):
Worker("eth"),
m_vc(_dbPath),
m_bc(_dbPath, !m_vc.ok() || _forceClean),
- m_gp(weiPerCent),
+ m_gp(_gp),
m_stateDB(State::openDB(_dbPath, !m_vc.ok() || _forceClean)),
m_preMine(Address(), m_stateDB),
m_postMine(Address(), m_stateDB)
{
- m_gp.updateQuartiles(m_bc);
+ m_gp->update(m_bc);
m_host = _extNet->registerCapability(new EthereumHost(m_bc, m_tq, m_bq, _networkId));
@@ -620,7 +662,7 @@ void Client::doWork()
// returns h256s as blooms, once for each transaction.
cwork << "postSTATE <== TQ";
- TransactionReceipts newPendingReceipts = m_postMine.sync(m_bc, m_tq, m_gp);
+ TransactionReceipts newPendingReceipts = m_postMine.sync(m_bc, m_tq, *m_gp);
if (newPendingReceipts.size())
{
for (size_t i = 0; i < newPendingReceipts.size(); i++)
diff --git a/libethereum/Client.h b/libethereum/Client.h
index 677c70977..9cbfd7989 100644
--- a/libethereum/Client.h
+++ b/libethereum/Client.h
@@ -160,6 +160,26 @@ private:
State m_state;
};
+class BasicGasPricer: public GasPricer
+{
+public:
+ explicit BasicGasPricer(u256 _weiPerRef, u256 _refsPerBlock): m_weiPerRef(_weiPerRef), m_refsPerBlock(_refsPerBlock) {}
+
+ void setRefPrice(u256 _weiPerRef) { m_weiPerRef = _weiPerRef; }
+ void setRefBlockFees(u256 _refsPerBlock) { m_refsPerBlock = _refsPerBlock; }
+
+ u256 ask(State const&) const override { return m_weiPerRef * m_refsPerBlock / m_gasPerBlock; }
+ u256 bid(TransactionPriority _p = TransactionPriority::Medium) const override { return m_octiles[(int)_p] > 0 ? m_octiles[(int)_p] : (m_weiPerRef * m_refsPerBlock / m_gasPerBlock); }
+
+ void update(BlockChain const& _bc) override;
+
+private:
+ u256 m_weiPerRef;
+ u256 m_refsPerBlock;
+ u256 m_gasPerBlock = 1000000;
+ std::array m_octiles;
+};
+
/**
* @brief Main API hub for interfacing with Ethereum.
*/
@@ -179,7 +199,7 @@ public:
explicit Client(
p2p::Host* _host,
- u256 _weiPerCent,
+ std::shared_ptr _gpForAdoption, // pass it in with new.
std::string const& _dbPath = std::string(),
bool _forceClean = false,
u256 _networkId = 0,
@@ -189,6 +209,9 @@ public:
/// Destructor.
virtual ~Client();
+ /// Resets the gas pricer to some other object.
+ void setGasPricer(std::shared_ptr _gp) { m_gp = _gp; }
+
/// Submits the given message-call transaction.
virtual void transact(Secret _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo);
@@ -361,7 +384,7 @@ private:
CanonBlockChain m_bc; ///< Maintains block database.
TransactionQueue m_tq; ///< Maintains a list of incoming transactions not yet in a block on the blockchain.
BlockQueue m_bq; ///< Maintains a list of incoming blocks not yet on the blockchain (to be imported).
- GasPricer m_gp; ///< The gas pricer.
+ std::shared_ptr m_gp; ///< The gas pricer.
mutable SharedMutex x_stateDB; ///< Lock on the state DB, effectively a lock on m_postMine.
OverlayDB m_stateDB; ///< Acts as the central point for the state database, so multiple States can share it.
diff --git a/libethereum/State.cpp b/libethereum/State.cpp
index e405f5cb8..d1e430dbe 100644
--- a/libethereum/State.cpp
+++ b/libethereum/State.cpp
@@ -464,45 +464,6 @@ TransactionReceipts State::sync(BlockChain const& _bc, TransactionQueue& _tq, Ga
return ret;
}
-void GasPricer::updateQuartiles(BlockChain const& _bc)
-{
- unsigned c = 0;
- h256 p = _bc.currentHash();
-
- map dist;
- unsigned total;
- while (c < 1000 && p)
- {
- BlockInfo bi = _bc.info(p);
- if (bi.transactionsRoot != EmptyTrie)
- {
- auto bb = _bc.block(p);
- RLP r(bb);
- BlockReceipts brs(_bc.receipts(bi.hash));
- for (unsigned i = 0; i < r[1].size(); ++i)
- {
- auto gu = brs.receipts[i].gasUsed();
- dist[Transaction(r[1][i].data(), CheckSignature::None).gasPrice()] += (unsigned)brs.receipts[i].gasUsed();
- total += (unsigned)gu;
- }
- }
- p = bi.parentHash;
- ++c;
- }
- if (total > 0)
- {
- unsigned t = 0;
- unsigned q = 1;
- for (auto const& i: dist)
- {
- for (; t <= total * q / 4 && t + i.second > total * q / 4; ++q)
- m_quartiles[q - 1] = i.first;
- if (q > 3)
- break;
- }
- }
-}
-
u256 State::enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce)
{
// m_currentBlock is assumed to be prepopulated and reset.
diff --git a/libethereum/State.h b/libethereum/State.h
index 49e353b1e..78ec85f38 100644
--- a/libethereum/State.h
+++ b/libethereum/State.h
@@ -47,6 +47,7 @@ namespace eth
{
class BlockChain;
+class State;
struct StateChat: public LogChannel { static const char* name() { return "-S-"; } static const int verbosity = 4; };
struct StateTrace: public LogChannel { static const char* name() { return "=S="; } static const int verbosity = 7; };
@@ -55,7 +56,32 @@ struct StateSafeExceptions: public LogChannel { static const char* name() { retu
enum class BaseState { Empty, CanonGenesis };
-class GasPricer;
+enum class TransactionPriority
+{
+ Lowest = 0,
+ Low = 2,
+ Medium = 4,
+ High = 6,
+ Highest = 8
+};
+
+class GasPricer
+{
+public:
+ GasPricer() {}
+
+ virtual u256 ask(State const&) const = 0;
+ virtual u256 bid(TransactionPriority _p = TransactionPriority::Medium) const = 0;
+
+ virtual void update(BlockChain const&) {}
+};
+
+class TrivialGasPricer: public GasPricer
+{
+protected:
+ u256 ask(State const&) const override { return 10 * szabo; }
+ u256 bid(TransactionPriority = TransactionPriority::Medium) const override { return 10 * szabo; }
+};
/**
* @brief Model of the current state of the ledger.
@@ -153,6 +179,7 @@ public:
/// Like sync but only operate on _tq, killing the invalid/old ones.
bool cull(TransactionQueue& _tq) const;
+ /// Returns the last few block hashes of the current chain.
LastHashes getLastHashes(BlockChain const& _bc, unsigned _n) const;
/// Execute a given transaction.
@@ -370,32 +397,6 @@ void commit(std::map const& _cache, DB& _db, SecureTrieDB m_quartiles;
-};
-
}
}
diff --git a/test/blockchain.cpp b/test/blockchain.cpp
index ccbc84956..0e1128ef9 100644
--- a/test/blockchain.cpp
+++ b/test/blockchain.cpp
@@ -87,7 +87,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
// get txs
TransactionQueue txs;
- GasPricer gp(10000);
+ TrivialGasPricer gp;
BOOST_REQUIRE(blObj.count("transactions"));
for (auto const& txObj: blObj["transactions"].get_array())
{