Browse Source

Merge branch 'develop' into new_jsonrpc

Conflicts:
	libweb3jsonrpc/WebThreeStubServerBase.cpp
cl-refactor
Marek Kotewicz 10 years ago
parent
commit
7145743f67
  1. 2
      CMakeLists.txt
  2. 2
      alethzero/CMakeLists.txt
  3. 14
      alethzero/Main.ui
  4. 4
      cmake/EthDependencies.cmake
  5. 35
      libethcore/BlockInfo.cpp
  6. 21
      libethcore/BlockInfo.h
  7. 30
      libethereum/Client.cpp
  8. 14
      libethereum/Client.h
  9. 65
      libethereum/State.cpp
  10. 30
      libethereum/State.h
  11. 2
      libweb3jsonrpc/WebThreeStubServerBase.cpp
  12. 169
      rlp/main.cpp
  13. 13
      test/blockchain.cpp
  14. 2
      test/dagger.cpp

2
CMakeLists.txt

@ -212,7 +212,7 @@ if (NOT JUSTTESTS)
if (ETH_HAVE_WEBENGINE) if (ETH_HAVE_WEBENGINE)
add_subdirectory(alethzero) add_subdirectory(alethzero)
add_subdirectory(third) # add_subdirectory(third) // reenable once not qtwebkit.
endif() endif()
add_subdirectory(mix) add_subdirectory(mix)

2
alethzero/CMakeLists.txt

@ -41,8 +41,6 @@ add_dependencies(${EXECUTABLE} BuildInfo.h)
target_link_libraries(${EXECUTABLE} Qt5::Core) target_link_libraries(${EXECUTABLE} Qt5::Core)
target_link_libraries(${EXECUTABLE} Qt5::Widgets) target_link_libraries(${EXECUTABLE} Qt5::Widgets)
target_link_libraries(${EXECUTABLE} Qt5::WebKit)
target_link_libraries(${EXECUTABLE} Qt5::WebKitWidgets)
target_link_libraries(${EXECUTABLE} Qt5::WebEngine) target_link_libraries(${EXECUTABLE} Qt5::WebEngine)
target_link_libraries(${EXECUTABLE} Qt5::WebEngineWidgets) target_link_libraries(${EXECUTABLE} Qt5::WebEngineWidgets)
target_link_libraries(${EXECUTABLE} webthree) target_link_libraries(${EXECUTABLE} webthree)

14
alethzero/Main.ui

@ -807,13 +807,7 @@
<number>0</number> <number>0</number>
</property> </property>
<item> <item>
<widget class="QWebView" name="jsConsole"> <widget class="QWebEngineView" name="jsConsole" native="true"/>
<property name="url">
<url>
<string>about:blank</string>
</url>
</property>
</widget>
</item> </item>
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout_9"> <layout class="QHBoxLayout" name="horizontalLayout_9">
@ -1668,11 +1662,6 @@ font-size: 14pt</string>
</widget> </widget>
<layoutdefault spacing="6" margin="11"/> <layoutdefault spacing="6" margin="11"/>
<customwidgets> <customwidgets>
<customwidget>
<class>QWebView</class>
<extends>QWidget</extends>
<header>QtWebKitWidgets/QWebView</header>
</customwidget>
<customwidget> <customwidget>
<class>MiningView</class> <class>MiningView</class>
<extends>QWidget</extends> <extends>QWidget</extends>
@ -1702,7 +1691,6 @@ font-size: 14pt</string>
<tabstop>log</tabstop> <tabstop>log</tabstop>
<tabstop>post</tabstop> <tabstop>post</tabstop>
<tabstop>verbosity</tabstop> <tabstop>verbosity</tabstop>
<tabstop>jsConsole</tabstop>
<tabstop>tabWidget</tabstop> <tabstop>tabWidget</tabstop>
<tabstop>urlEdit</tabstop> <tabstop>urlEdit</tabstop>
<tabstop>idealPeers</tabstop> <tabstop>idealPeers</tabstop>

4
cmake/EthDependencies.cmake

@ -120,8 +120,8 @@ if (NOT HEADLESS)
find_package (Qt5Qml REQUIRED) find_package (Qt5Qml REQUIRED)
find_package (Qt5Network REQUIRED) find_package (Qt5Network REQUIRED)
find_package (Qt5Widgets REQUIRED) find_package (Qt5Widgets REQUIRED)
find_package (Qt5WebKit REQUIRED) find_package (Qt5WebEngine REQUIRED)
find_package (Qt5WebKitWidgets REQUIRED) find_package (Qt5WebEngineWidgets REQUIRED)
# we need to find path to macdeployqt on mac # we need to find path to macdeployqt on mac
if (APPLE) if (APPLE)

35
libethcore/BlockInfo.cpp

@ -35,9 +35,9 @@ BlockInfo::BlockInfo(): timestamp(Invalid256)
{ {
} }
BlockInfo::BlockInfo(bytesConstRef _block, bool _checkNonce) BlockInfo::BlockInfo(bytesConstRef _block, Strictness _s)
{ {
populate(_block, _checkNonce); populate(_block, _s);
} }
void BlockInfo::setEmpty() void BlockInfo::setEmpty()
@ -61,10 +61,10 @@ void BlockInfo::setEmpty()
hash = headerHash(WithNonce); hash = headerHash(WithNonce);
} }
BlockInfo BlockInfo::fromHeader(bytesConstRef _block) BlockInfo BlockInfo::fromHeader(bytesConstRef _block, Strictness _s)
{ {
BlockInfo ret; BlockInfo ret;
ret.populateFromHeader(RLP(_block)); ret.populateFromHeader(RLP(_block), _s);
return ret; return ret;
} }
@ -89,7 +89,7 @@ h256 BlockInfo::headerHash(bytesConstRef _block)
return sha3(RLP(_block)[0].data()); return sha3(RLP(_block)[0].data());
} }
void BlockInfo::populateFromHeader(RLP const& _header, bool _checkNonce) void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s)
{ {
hash = dev::sha3(_header.data()); hash = dev::sha3(_header.data());
@ -121,30 +121,33 @@ void BlockInfo::populateFromHeader(RLP const& _header, bool _checkNonce)
} }
// check it hashes according to proof of work or that it's the genesis block. // check it hashes according to proof of work or that it's the genesis block.
if (_checkNonce && parentHash && !ProofOfWork::verify(*this)) if (_s == CheckEverything && parentHash && !ProofOfWork::verify(*this))
BOOST_THROW_EXCEPTION(InvalidBlockNonce() << errinfo_hash256(headerHash(WithoutNonce)) << errinfo_nonce(nonce) << errinfo_difficulty(difficulty)); BOOST_THROW_EXCEPTION(InvalidBlockNonce() << errinfo_hash256(headerHash(WithoutNonce)) << errinfo_nonce(nonce) << errinfo_difficulty(difficulty));
if (gasUsed > gasLimit) if (_s != CheckNothing)
BOOST_THROW_EXCEPTION(TooMuchGasUsed() << RequirementError(bigint(gasLimit), bigint(gasUsed)) ); {
if (gasUsed > gasLimit)
BOOST_THROW_EXCEPTION(TooMuchGasUsed() << RequirementError(bigint(gasLimit), bigint(gasUsed)) );
if (difficulty < c_minimumDifficulty) if (difficulty < c_minimumDifficulty)
BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError(bigint(c_minimumDifficulty), bigint(difficulty)) ); BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError(bigint(c_minimumDifficulty), bigint(difficulty)) );
if (gasLimit < c_minGasLimit) if (gasLimit < c_minGasLimit)
BOOST_THROW_EXCEPTION(InvalidGasLimit() << RequirementError(bigint(c_minGasLimit), bigint(gasLimit)) ); BOOST_THROW_EXCEPTION(InvalidGasLimit() << RequirementError(bigint(c_minGasLimit), bigint(gasLimit)) );
if (number && extraData.size() > c_maximumExtraDataSize) if (number && extraData.size() > c_maximumExtraDataSize)
BOOST_THROW_EXCEPTION(ExtraDataTooBig() << RequirementError(bigint(c_maximumExtraDataSize), bigint(extraData.size()))); BOOST_THROW_EXCEPTION(ExtraDataTooBig() << RequirementError(bigint(c_maximumExtraDataSize), bigint(extraData.size())));
}
} }
void BlockInfo::populate(bytesConstRef _block, bool _checkNonce) void BlockInfo::populate(bytesConstRef _block, Strictness _s)
{ {
RLP root(_block); RLP root(_block);
RLP header = root[0]; RLP header = root[0];
if (!header.isList()) if (!header.isList())
BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block header needs to be a list") << BadFieldError(0, header.data().toString())); BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block header needs to be a list") << BadFieldError(0, header.data().toString()));
populateFromHeader(header, _checkNonce); populateFromHeader(header, _s);
if (!root[1].isList()) if (!root[1].isList())
BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block transactions need to be a list") << BadFieldError(1, root[1].data().toString())); BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block transactions need to be a list") << BadFieldError(1, root[1].data().toString()));

21
libethcore/BlockInfo.h

@ -36,6 +36,13 @@ enum IncludeNonce
WithNonce = 1 WithNonce = 1
}; };
enum Strictness
{
CheckEverything,
IgnoreNonce,
CheckNothing
};
/** @brief Encapsulation of a block header. /** @brief Encapsulation of a block header.
* Class to contain all of a block header's data. It is able to parse a block header and populate * Class to contain all of a block header's data. It is able to parse a block header and populate
* from some given RLP block serialisation with the static fromHeader(), through the method * from some given RLP block serialisation with the static fromHeader(), through the method
@ -79,14 +86,14 @@ public:
Nonce nonce; Nonce nonce;
BlockInfo(); BlockInfo();
explicit BlockInfo(bytes const& _block): BlockInfo(&_block) {} explicit BlockInfo(bytes const& _block, Strictness _s = CheckEverything): BlockInfo(&_block, _s) {}
explicit BlockInfo(bytesConstRef _block, bool _checkNonce = true); explicit BlockInfo(bytesConstRef _block, Strictness _s = CheckEverything);
static h256 headerHash(bytes const& _block) { return headerHash(&_block); } static h256 headerHash(bytes const& _block) { return headerHash(&_block); }
static h256 headerHash(bytesConstRef _block); static h256 headerHash(bytesConstRef _block);
static BlockInfo fromHeader(bytes const& _block) { return fromHeader(bytesConstRef(&_block)); } static BlockInfo fromHeader(bytes const& _block, Strictness _s = CheckEverything) { return fromHeader(bytesConstRef(&_block), _s); }
static BlockInfo fromHeader(bytesConstRef _block); static BlockInfo fromHeader(bytesConstRef _block, Strictness _s = CheckEverything);
explicit operator bool() const { return timestamp != Invalid256; } explicit operator bool() const { return timestamp != Invalid256; }
@ -113,9 +120,9 @@ public:
void setEmpty(); void setEmpty();
void populateFromHeader(RLP const& _header, bool _checkNonce = true); void populateFromHeader(RLP const& _header, Strictness _s = CheckEverything);
void populate(bytesConstRef _block, bool _checkNonce = true); void populate(bytesConstRef _block, Strictness _s = CheckEverything);
void populate(bytes const& _block, bool _checkNonce = true) { populate(&_block, _checkNonce); } void populate(bytes const& _block, Strictness _s = CheckEverything) { populate(&_block, _s); }
void verifyInternals(bytesConstRef _block) const; void verifyInternals(bytesConstRef _block) const;
void verifyParent(BlockInfo const& _parent) const; void verifyParent(BlockInfo const& _parent) const;
void populateFromParent(BlockInfo const& parent); void populateFromParent(BlockInfo const& parent);

30
libethereum/Client.cpp

@ -64,10 +64,38 @@ Client::Client(p2p::Host* _extNet, std::string const& _dbPath, bool _forceClean,
Worker("eth"), Worker("eth"),
m_vc(_dbPath), m_vc(_dbPath),
m_bc(_dbPath, !m_vc.ok() || _forceClean), m_bc(_dbPath, !m_vc.ok() || _forceClean),
m_gp(u256("60000000000000")),
m_stateDB(State::openDB(_dbPath, !m_vc.ok() || _forceClean)), m_stateDB(State::openDB(_dbPath, !m_vc.ok() || _forceClean)),
m_preMine(Address(), m_stateDB), m_preMine(Address(), m_stateDB),
m_postMine(Address(), m_stateDB) m_postMine(Address(), m_stateDB)
{ {
m_gp.updateQuartiles(m_bc);
m_host = _extNet->registerCapability(new EthereumHost(m_bc, m_tq, m_bq, _networkId));
if (_miners > -1)
setMiningThreads(_miners);
else
setMiningThreads();
if (_dbPath.size())
Defaults::setDBPath(_dbPath);
m_vc.setOk();
doWork();
startWorking();
}
Client::Client(p2p::Host* _extNet, u256 weiPerCent, 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_stateDB(State::openDB(_dbPath, !m_vc.ok() || _forceClean)),
m_preMine(Address(), m_stateDB),
m_postMine(Address(), m_stateDB)
{
m_gp.updateQuartiles(m_bc);
m_host = _extNet->registerCapability(new EthereumHost(m_bc, m_tq, m_bq, _networkId)); m_host = _extNet->registerCapability(new EthereumHost(m_bc, m_tq, m_bq, _networkId));
if (_miners > -1) if (_miners > -1)
@ -592,7 +620,7 @@ void Client::doWork()
// returns h256s as blooms, once for each transaction. // returns h256s as blooms, once for each transaction.
cwork << "postSTATE <== TQ"; cwork << "postSTATE <== TQ";
TransactionReceipts newPendingReceipts = m_postMine.sync(m_bc, m_tq); TransactionReceipts newPendingReceipts = m_postMine.sync(m_bc, m_tq, m_gp);
if (newPendingReceipts.size()) if (newPendingReceipts.size())
{ {
for (size_t i = 0; i < newPendingReceipts.size(); i++) for (size_t i = 0; i < newPendingReceipts.size(); i++)

14
libethereum/Client.h

@ -177,6 +177,15 @@ public:
int _miners = -1 int _miners = -1
); );
explicit Client(
p2p::Host* _host,
u256 _weiPerCent,
std::string const& _dbPath = std::string(),
bool _forceClean = false,
u256 _networkId = 0,
int _miners = -1
);
/// Destructor. /// Destructor.
virtual ~Client(); virtual ~Client();
@ -355,6 +364,7 @@ private:
CanonBlockChain m_bc; ///< Maintains block database. CanonBlockChain m_bc; ///< Maintains block database.
TransactionQueue m_tq; ///< Maintains a list of incoming transactions not yet in a block on the blockchain. 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). BlockQueue m_bq; ///< Maintains a list of incoming blocks not yet on the blockchain (to be imported).
GasPricer m_gp; ///< The gas pricer.
mutable SharedMutex x_stateDB; ///< Lock on the state DB, effectively a lock on m_postMine. 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. OverlayDB m_stateDB; ///< Acts as the central point for the state database, so multiple States can share it.
@ -371,7 +381,9 @@ private:
bool m_paranoia = false; ///< Should we be paranoid about our state? bool m_paranoia = false; ///< Should we be paranoid about our state?
bool m_turboMining = false; ///< Don't squander all of our time mining actually just sleeping. bool m_turboMining = false; ///< Don't squander all of our time mining actually just sleeping.
bool m_forceMining = false; ///< Mine even when there are no transactions pending? bool m_forceMining = false; ///< Mine even when there are no transactions pending?
bool m_verifyOwnBlocks = true; ///< Shoudl be verify blocks that we mined? bool m_verifyOwnBlocks = true; ///< Should be verify blocks that we mined?
mutable Mutex m_filterLock; mutable Mutex m_filterLock;
std::map<h256, InstalledFilter> m_filters; std::map<h256, InstalledFilter> m_filters;

65
libethereum/State.cpp

@ -400,7 +400,7 @@ bool State::cull(TransactionQueue& _tq) const
return ret; return ret;
} }
TransactionReceipts State::sync(BlockChain const& _bc, TransactionQueue& _tq, bool* o_transactionQueueChanged) TransactionReceipts State::sync(BlockChain const& _bc, TransactionQueue& _tq, GasPricer const& _gp, bool* o_transactionQueueChanged)
{ {
// TRANSACTIONS // TRANSACTIONS
TransactionReceipts ret; TransactionReceipts ret;
@ -414,16 +414,20 @@ TransactionReceipts State::sync(BlockChain const& _bc, TransactionQueue& _tq, bo
for (auto const& i: ts) for (auto const& i: ts)
if (!m_transactionSet.count(i.first)) if (!m_transactionSet.count(i.first))
{ {
// don't have it yet! Execute it now.
try try
{ {
uncommitToMine(); Transaction t(i.second, CheckSignature::Sender);
// boost::timer t; if (t.gasPrice() >= _gp.ask(*this))
execute(lh, i.second); {
ret.push_back(m_receipts.back()); // don't have it yet! Execute it now.
_tq.noteGood(i); uncommitToMine();
++goodTxs; // boost::timer t;
// cnote << "TX took:" << t.elapsed() * 1000; execute(lh, i.second);
ret.push_back(m_receipts.back());
_tq.noteGood(i);
++goodTxs;
// cnote << "TX took:" << t.elapsed() * 1000;
}
} }
catch (InvalidNonce const& in) catch (InvalidNonce const& in)
{ {
@ -460,12 +464,51 @@ TransactionReceipts State::sync(BlockChain const& _bc, TransactionQueue& _tq, bo
return ret; return ret;
} }
void GasPricer::updateQuartiles(BlockChain const& _bc)
{
unsigned c = 0;
h256 p = _bc.currentHash();
map<u256, unsigned> 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) u256 State::enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce)
{ {
// m_currentBlock is assumed to be prepopulated and reset. // m_currentBlock is assumed to be prepopulated and reset.
#if !ETH_RELEASE #if !ETH_RELEASE
BlockInfo bi(_block, _checkNonce); BlockInfo bi(_block, _checkNonce ? CheckEverything : IgnoreNonce);
assert(m_previousBlock.hash == bi.parentHash); assert(m_previousBlock.hash == bi.parentHash);
assert(m_currentBlock.parentHash == bi.parentHash); assert(m_currentBlock.parentHash == bi.parentHash);
assert(rootHash() == m_previousBlock.stateRoot); assert(rootHash() == m_previousBlock.stateRoot);
@ -475,7 +518,7 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce)
BOOST_THROW_EXCEPTION(InvalidParentHash()); BOOST_THROW_EXCEPTION(InvalidParentHash());
// Populate m_currentBlock with the correct values. // Populate m_currentBlock with the correct values.
m_currentBlock.populate(_block, _checkNonce); m_currentBlock.populate(_block, _checkNonce ? CheckEverything : IgnoreNonce);
m_currentBlock.verifyInternals(_block); m_currentBlock.verifyInternals(_block);
// cnote << "playback begins:" << m_state.root(); // cnote << "playback begins:" << m_state.root();

30
libethereum/State.h

@ -55,6 +55,8 @@ struct StateSafeExceptions: public LogChannel { static const char* name() { retu
enum class BaseState { Empty, CanonGenesis }; enum class BaseState { Empty, CanonGenesis };
class GasPricer;
/** /**
* @brief Model of the current state of the ledger. * @brief Model of the current state of the ledger.
* Maintains current ledger (m_current) as a fast hash-map. This is hashed only when required (i.e. to create or verify a block). * Maintains current ledger (m_current) as a fast hash-map. This is hashed only when required (i.e. to create or verify a block).
@ -147,7 +149,7 @@ public:
/// @returns a list of receipts one for each transaction placed from the queue into the state. /// @returns a list of receipts one for each transaction placed from the queue into the state.
/// @a o_transactionQueueChanged boolean pointer, the value of which will be set to true if the transaction queue /// @a o_transactionQueueChanged boolean pointer, the value of which will be set to true if the transaction queue
/// changed and the pointer is non-null /// changed and the pointer is non-null
TransactionReceipts sync(BlockChain const& _bc, TransactionQueue& _tq, bool* o_transactionQueueChanged = nullptr); TransactionReceipts sync(BlockChain const& _bc, TransactionQueue& _tq, GasPricer const& _gp, bool* o_transactionQueueChanged = nullptr);
/// Like sync but only operate on _tq, killing the invalid/old ones. /// Like sync but only operate on _tq, killing the invalid/old ones.
bool cull(TransactionQueue& _tq) const; bool cull(TransactionQueue& _tq) const;
@ -368,6 +370,32 @@ void commit(std::map<Address, Account> const& _cache, DB& _db, SecureTrieDB<Addr
} }
} }
enum class TransactionPriority
{
Low = 0,
Medium = 1,
High = 2
};
class GasPricer
{
public:
explicit GasPricer(u256 _weiPerCent): m_weiPerCent(_weiPerCent) {}
u256 ask(State const&) const { return m_weiPerCent * m_centsPerBlock / m_gasPerBlock; }
u256 bid(TransactionPriority _p = TransactionPriority::Medium) const { return m_quartiles[(int)_p]; }
void updateRefPrice(u256 _weiPerCent) { m_weiPerCent = _weiPerCent; }
void updateRefRequirement(u256 _centsPerBlock) { m_centsPerBlock = _centsPerBlock; }
void updateQuartiles(BlockChain const& _bc);
private:
u256 m_weiPerCent;
u256 m_centsPerBlock = 15;
u256 m_gasPerBlock = 1000000;
std::array<u256, 100> m_quartiles;
};
} }
} }

2
libweb3jsonrpc/WebThreeStubServerBase.cpp

@ -511,7 +511,7 @@ string WebThreeStubServerBase::eth_sendTransaction(Json::Value const& _json)
if (t.creation) if (t.creation)
ret = toJS(right160(sha3(rlpList(t.from, client()->countAt(t.from)))));; ret = toJS(right160(sha3(rlpList(t.from, client()->countAt(t.from)))));;
if (!t.gasPrice) if (!t.gasPrice)
t.gasPrice = 10 * dev::eth::szabo; t.gasPrice = 10 * dev::eth::szabo; // TODO: should be determined by user somehow.
if (!t.gas) if (!t.gas)
t.gas = min<u256>(client()->gasLimitRemaining(), client()->balanceAt(t.from) / t.gasPrice); t.gas = min<u256>(client()->gasLimitRemaining(), client()->balanceAt(t.from) / t.gasPrice);

169
rlp/main.cpp

@ -22,11 +22,13 @@
#include <fstream> #include <fstream>
#include <iostream> #include <iostream>
#include <boost/algorithm/string.hpp> #include <boost/algorithm/string.hpp>
#include "../test/JsonSpiritHeaders.h"
#include <libdevcore/CommonIO.h> #include <libdevcore/CommonIO.h>
#include <libdevcore/RLP.h> #include <libdevcore/RLP.h>
#include <libdevcrypto/SHA3.h> #include <libdevcrypto/SHA3.h>
using namespace std; using namespace std;
using namespace dev; using namespace dev;
namespace js = json_spirit;
void help() void help()
{ {
@ -42,6 +44,7 @@ void help()
<< " --force-hex Force all data to be rendered as raw hex." << endl << " --force-hex Force all data to be rendered as raw hex." << endl
<< " -l,--list-archive List the items in the RLP list by hash and size." << endl << " -l,--list-archive List the items in the RLP list by hash and size." << endl
<< " -e,--extract-archive Extract all items in the RLP list, named by hash." << endl << " -e,--extract-archive Extract all items in the RLP list, named by hash." << endl
<< " -c,--create Given a simplified JSON string, output the RLP." << endl
<< "General options:" << endl << "General options:" << endl
<< " -L,--lenience Try not to bomb out early if possible." << endl << " -L,--lenience Try not to bomb out early if possible." << endl
<< " -x,--hex,--base-16 Treat input RLP as hex encoded data." << endl << " -x,--hex,--base-16 Treat input RLP as hex encoded data." << endl
@ -63,6 +66,7 @@ enum class Mode {
ListArchive, ListArchive,
ExtractArchive, ExtractArchive,
Render, Render,
Create
}; };
enum class Encoding { enum class Encoding {
@ -74,6 +78,10 @@ enum class Encoding {
bool isAscii(string const& _s) bool isAscii(string const& _s)
{ {
// Always hex-encode anything beginning with 0x to avoid ambiguity.
if (_s.size() >= 2 && _s.substr(0, 2) == "0x")
return false;
for (char c: _s) for (char c: _s)
if (c < 32) if (c < 32)
return false; return false;
@ -87,6 +95,7 @@ public:
{ {
string indent = " "; string indent = " ";
bool hexInts = false; bool hexInts = false;
bool hexPrefix = true;
bool forceString = true; bool forceString = true;
bool escapeAll = false; bool escapeAll = false;
bool forceHex = false; bool forceHex = false;
@ -100,14 +109,14 @@ public:
m_out << "null"; m_out << "null";
else if (_d.isInt()) else if (_d.isInt())
if (m_prefs.hexInts) if (m_prefs.hexInts)
m_out << toHex(toCompactBigEndian(_d.toInt<bigint>(RLP::LaisezFaire), 1), 1); m_out << (m_prefs.hexPrefix ? "0x" : "") << toHex(toCompactBigEndian(_d.toInt<bigint>(RLP::LaisezFaire), 1), 1);
else else
m_out << _d.toInt<bigint>(RLP::LaisezFaire); m_out << _d.toInt<bigint>(RLP::LaisezFaire);
else if (_d.isData()) else if (_d.isData())
if (m_prefs.forceString || (!m_prefs.forceHex && isAscii(_d.toString()))) if (m_prefs.forceString || (!m_prefs.forceHex && isAscii(_d.toString())))
m_out << escaped(_d.toString(), m_prefs.escapeAll); m_out << escaped(_d.toString(), m_prefs.escapeAll);
else else
m_out << toHex(_d.data()); m_out << (m_prefs.hexPrefix ? "0x" : "") << toHex(_d.data());
else if (_d.isList()) else if (_d.isList())
{ {
m_out << "["; m_out << "[";
@ -147,6 +156,8 @@ int main(int argc, char** argv)
help(); help();
else if (arg == "-r" || arg == "--render") else if (arg == "-r" || arg == "--render")
mode = Mode::Render; mode = Mode::Render;
else if (arg == "-c" || arg == "--create")
mode = Mode::Create;
else if ((arg == "-i" || arg == "--indent") && argc > i) else if ((arg == "-i" || arg == "--indent") && argc > i)
prefs.indent = argv[++i]; prefs.indent = argv[++i];
else if (arg == "--hex-ints") else if (arg == "--hex-ints")
@ -183,48 +194,53 @@ int main(int argc, char** argv)
in.push_back((byte)i); in.push_back((byte)i);
else else
in = contents(inputFile); in = contents(inputFile);
if (encoding == Encoding::Auto)
bytes b;
if (mode != Mode::Create)
{ {
encoding = Encoding::Hex; if (encoding == Encoding::Auto)
for (char b: in) {
if (b != '\n' && b != ' ' && b != '\t') encoding = Encoding::Hex;
{ for (char b: in)
if (encoding == Encoding::Hex && (b < '0' || b > '9' ) && (b < 'a' || b > 'f' ) && (b < 'A' || b > 'F' )) if (b != '\n' && b != ' ' && b != '\t')
{
cerr << "'" << b << "':" << (int)b << endl;
encoding = Encoding::Base64;
}
if (encoding == Encoding::Base64 && (b < '0' || b > '9' ) && (b < 'a' || b > 'z' ) && (b < 'A' || b > 'Z' ) && b != '+' && b != '/')
{ {
encoding = Encoding::Binary; if (encoding == Encoding::Hex && (b < '0' || b > '9' ) && (b < 'a' || b > 'f' ) && (b < 'A' || b > 'F' ))
break; {
cerr << "'" << b << "':" << (int)b << endl;
encoding = Encoding::Base64;
}
if (encoding == Encoding::Base64 && (b < '0' || b > '9' ) && (b < 'a' || b > 'z' ) && (b < 'A' || b > 'Z' ) && b != '+' && b != '/')
{
encoding = Encoding::Binary;
break;
}
} }
} }
} switch (encoding)
bytes b; {
switch (encoding) case Encoding::Hex:
{ {
case Encoding::Hex: string s = asString(in);
{ boost::algorithm::replace_all(s, " ", "");
string s = asString(in); boost::algorithm::replace_all(s, "\n", "");
boost::algorithm::replace_all(s, " ", ""); boost::algorithm::replace_all(s, "\t", "");
boost::algorithm::replace_all(s, "\n", ""); b = fromHex(s);
boost::algorithm::replace_all(s, "\t", ""); break;
b = fromHex(s); }
break; case Encoding::Base64:
} {
case Encoding::Base64: string s = asString(in);
{ boost::algorithm::replace_all(s, " ", "");
string s = asString(in); boost::algorithm::replace_all(s, "\n", "");
boost::algorithm::replace_all(s, " ", ""); boost::algorithm::replace_all(s, "\t", "");
boost::algorithm::replace_all(s, "\n", ""); b = fromBase64(s);
boost::algorithm::replace_all(s, "\t", ""); break;
b = fromBase64(s); }
break; default:
} swap(b, in);
default: break;
swap(b, in); }
break;
} }
try try
@ -281,6 +297,77 @@ int main(int argc, char** argv)
cout << endl; cout << endl;
break; break;
} }
case Mode::Create:
{
vector<js::mValue> v(1);
try {
js::read_string(asString(in), v[0]);
}
catch (...)
{
cerr << "Error: Invalid format; bad JSON." << endl;
exit(1);
}
RLPStream out;
while (!v.empty())
{
auto vb = v.back();
v.pop_back();
switch (vb.type())
{
case js::array_type:
{
js::mArray a = vb.get_array();
out.appendList(a.size());
for (int i = a.size() - 1; i >= 0; --i)
v.push_back(a[i]);
break;
}
case js::str_type:
{
string const& s = vb.get_str();
if (s.size() >= 2 && s.substr(0, 2) == "0x")
out << fromHex(s);
else
{
// assume it's a normal JS escaped string.
bytes ss;
ss.reserve(s.size());
for (unsigned i = 0; i < s.size(); ++i)
if (s[i] == '\\' && i + 1 < s.size())
{
if (s[++i] == 'x' && i + 2 < s.size())
ss.push_back(fromHex(s.substr(i, 2))[0]);
}
else if (s[i] != '\\')
ss.push_back((byte)s[i]);
out << ss;
}
break;
}
case js::int_type:
out << vb.get_int();
break;
default:
cerr << "ERROR: Unsupported type in JSON." << endl;
if (!lenience)
exit(1);
}
}
switch (encoding)
{
case Encoding::Hex: case Encoding::Auto:
cout << toHex(out.out()) << endl;
break;
case Encoding::Base64:
cout << toBase64(&out.out()) << endl;
break;
case Encoding::Binary:
cout.write((char const*)out.out().data(), out.out().size());
break;
}
break;
}
default:; default:;
} }
} }

13
test/blockchain.cpp

@ -87,6 +87,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
// get txs // get txs
TransactionQueue txs; TransactionQueue txs;
GasPricer gp(10000);
BOOST_REQUIRE(blObj.count("transactions")); BOOST_REQUIRE(blObj.count("transactions"));
for (auto const& txObj: blObj["transactions"].get_array()) for (auto const& txObj: blObj["transactions"].get_array())
{ {
@ -131,7 +132,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
try try
{ {
state.sync(bc); state.sync(bc);
state.sync(bc,txs); state.sync(bc, txs, gp);
state.commitToMine(bc); state.commitToMine(bc);
MineInfo info; MineInfo info;
for (info.completed = false; !info.completed; info = state.mine()) {} for (info.completed = false; !info.completed; info = state.mine()) {}
@ -281,7 +282,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
BlockInfo blockHeaderFromFields; BlockInfo blockHeaderFromFields;
const bytes c_rlpBytesBlockHeader = createBlockRLPFromFields(tObj); const bytes c_rlpBytesBlockHeader = createBlockRLPFromFields(tObj);
const RLP c_blockHeaderRLP(c_rlpBytesBlockHeader); const RLP c_blockHeaderRLP(c_rlpBytesBlockHeader);
blockHeaderFromFields.populateFromHeader(c_blockHeaderRLP, false); blockHeaderFromFields.populateFromHeader(c_blockHeaderRLP, IgnoreNonce);
BlockInfo blockFromRlp = bc.info(); BlockInfo blockFromRlp = bc.info();
@ -381,7 +382,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
BlockInfo uncleBlockHeader; BlockInfo uncleBlockHeader;
try try
{ {
uncleBlockHeader.populateFromHeader(c_uRLP, true); uncleBlockHeader.populateFromHeader(c_uRLP);
} }
catch(...) catch(...)
{ {
@ -395,7 +396,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
for (auto const& uRLP: root[2]) for (auto const& uRLP: root[2])
{ {
BlockInfo uBl; BlockInfo uBl;
uBl.populateFromHeader(uRLP, true); uBl.populateFromHeader(uRLP);
uBlHsFromRlp.push_back(uBl); uBlHsFromRlp.push_back(uBl);
} }
@ -538,7 +539,7 @@ void overwriteBlockHeader(BlockInfo& _current_BlockHeader, mObject& _blObj)
// take the blockheader as is // take the blockheader as is
const bytes c_blockRLP = createBlockRLPFromFields(_blObj["blockHeader"].get_obj()); const bytes c_blockRLP = createBlockRLPFromFields(_blObj["blockHeader"].get_obj());
const RLP c_bRLP(c_blockRLP); const RLP c_bRLP(c_blockRLP);
_current_BlockHeader.populateFromHeader(c_bRLP, false); _current_BlockHeader.populateFromHeader(c_bRLP, IgnoreNonce);
} }
} }
@ -551,7 +552,7 @@ BlockInfo constructBlock(mObject& _o)
// construct genesis block // construct genesis block
const bytes c_blockRLP = createBlockRLPFromFields(_o); const bytes c_blockRLP = createBlockRLPFromFields(_o);
const RLP c_bRLP(c_blockRLP); const RLP c_bRLP(c_blockRLP);
ret.populateFromHeader(c_bRLP, false); ret.populateFromHeader(c_bRLP, IgnoreNonce);
} }
catch (Exception const& _e) catch (Exception const& _e)
{ {

2
test/dagger.cpp

@ -55,7 +55,7 @@ BOOST_AUTO_TEST_CASE(basic_test)
cnote << i.first; cnote << i.first;
js::mObject& o = i.second.get_obj(); js::mObject& o = i.second.get_obj();
vector<pair<string, string>> ss; vector<pair<string, string>> ss;
BlockInfo header = BlockInfo::fromHeader(fromHex(o["header"].get_str())); BlockInfo header = BlockInfo::fromHeader(fromHex(o["header"].get_str()), CheckNothing);
h256 headerHash(o["header_hash"].get_str()); h256 headerHash(o["header_hash"].get_str());
Nonce nonce(o["nonce"].get_str()); Nonce nonce(o["nonce"].get_str());
BOOST_REQUIRE_EQUAL(headerHash, header.headerHash(WithoutNonce)); BOOST_REQUIRE_EQUAL(headerHash, header.headerHash(WithoutNonce));

Loading…
Cancel
Save