Browse Source

Merge branch 'develop' into p2p

cl-refactor
subtly 10 years ago
parent
commit
ec4cb1118b
  1. 28
      libethcore/ProofOfWork.h
  2. 103
      libethereum/Client.cpp
  3. 50
      libethereum/Client.h
  4. 5
      libethereum/Interface.h
  5. 12
      libethereum/Miner.cpp
  6. 28
      libethereum/Miner.h
  7. 18
      libethereum/State.cpp
  8. 4
      libethereum/State.h
  9. 47
      libsolidity/ExpressionCompiler.cpp
  10. 27
      libsolidity/Types.cpp
  11. 12
      libweb3jsonrpc/WebThreeStubServer.h
  12. 14
      libweb3jsonrpc/WebThreeStubServerBase.cpp
  13. 3
      libweb3jsonrpc/WebThreeStubServerBase.h
  14. 12
      libweb3jsonrpc/abstractwebthreestubserver.h
  15. 4
      libweb3jsonrpc/spec.json
  16. 2
      mix/MixClient.h
  17. 18
      test/SolidityEndToEndTest.cpp

28
libethcore/ProofOfWork.h

@ -51,7 +51,7 @@ class ProofOfWorkEngine: public Evaluator
public:
static bool verify(h256 const& _root, h256 const& _nonce, u256 const& _difficulty) { return (bigint)(u256)Evaluator::eval(_root, _nonce) <= (bigint(1) << 256) / _difficulty; }
inline MineInfo mine(h256& o_solution, h256 const& _root, u256 const& _difficulty, unsigned _msTimeout = 100, bool _continue = true, bool _turbo = false);
inline std::pair<MineInfo, h256> mine(h256 const& _root, u256 const& _difficulty, unsigned _msTimeout = 100, bool _continue = true, bool _turbo = false);
protected:
h256 m_last;
@ -79,14 +79,14 @@ using SHA3ProofOfWork = ProofOfWorkEngine<SHA3Evaluator>;
using ProofOfWork = SHA3ProofOfWork;
template <class Evaluator>
MineInfo ProofOfWorkEngine<Evaluator>::mine(h256& o_solution, h256 const& _root, u256 const& _difficulty, unsigned _msTimeout, bool _continue, bool _turbo)
std::pair<MineInfo, h256> ProofOfWorkEngine<Evaluator>::mine(h256 const& _root, u256 const& _difficulty, unsigned _msTimeout, bool _continue, bool _turbo)
{
MineInfo ret;
std::pair<MineInfo, h256> ret;
static std::mt19937_64 s_eng((time(0) + (unsigned)m_last));
u256 s = (m_last = h256::random(s_eng));
bigint d = (bigint(1) << 256) / _difficulty;
ret.requirement = log2((double)d);
ret.first.requirement = log2((double)d);
// 2^ 0 32 64 128 256
// [--------*-------------------------]
@ -95,20 +95,26 @@ MineInfo ProofOfWorkEngine<Evaluator>::mine(h256& o_solution, h256 const& _root,
auto startTime = std::chrono::steady_clock::now();
if (!_turbo)
std::this_thread::sleep_for(std::chrono::milliseconds(_msTimeout * 90 / 100));
for (; (std::chrono::steady_clock::now() - startTime) < std::chrono::milliseconds(_msTimeout) && _continue; s++, ret.hashes++)
double best = 1e99; // high enough to be effectively infinity :)
h256 solution;
unsigned h = 0;
for (; (std::chrono::steady_clock::now() - startTime) < std::chrono::milliseconds(_msTimeout) && _continue; s++, h++)
{
o_solution = (h256)s;
auto e = (bigint)(u256)Evaluator::eval(_root, o_solution);
ret.best = std::min<double>(ret.best, log2((double)e));
solution = (h256)s;
auto e = (bigint)(u256)Evaluator::eval(_root, solution);
best = std::min<double>(best, log2((double)e));
if (e <= d)
{
ret.completed = true;
ret.first.completed = true;
break;
}
}
ret.first.hashes = h;
ret.first.best = best;
ret.second = solution;
if (ret.completed)
assert(verify(_root, o_solution, _difficulty));
if (ret.first.completed)
assert(verify(_root, solution, _difficulty));
return ret;
}

103
libethereum/Client.cpp

@ -126,7 +126,7 @@ void Client::killChain()
m_tq.clear();
m_bq.clear();
m_miners.clear();
m_localMiners.clear();
m_preMine = State();
m_postMine = State();
@ -167,8 +167,8 @@ void Client::clearPending()
}
{
ReadGuard l(x_miners);
for (auto& m: m_miners)
ReadGuard l(x_localMiners);
for (auto& m: m_localMiners)
m.noteStateChange();
}
@ -320,8 +320,8 @@ void Client::appendFromNewBlock(h256 const& _block, h256Set& io_changed)
void Client::setForceMining(bool _enable)
{
m_forceMining = _enable;
ReadGuard l(x_miners);
for (auto& m: m_miners)
ReadGuard l(x_localMiners);
for (auto& m: m_localMiners)
m.noteStateChange();
}
@ -330,19 +330,19 @@ void Client::setMiningThreads(unsigned _threads)
stopMining();
auto t = _threads ? _threads : thread::hardware_concurrency();
WriteGuard l(x_miners);
m_miners.clear();
m_miners.resize(t);
WriteGuard l(x_localMiners);
m_localMiners.clear();
m_localMiners.resize(t);
unsigned i = 0;
for (auto& m: m_miners)
for (auto& m: m_localMiners)
m.setup(this, i++);
}
MineProgress Client::miningProgress() const
{
MineProgress ret;
ReadGuard l(x_miners);
for (auto& m: m_miners)
ReadGuard l(x_localMiners);
for (auto& m: m_localMiners)
ret.combine(m.miningProgress());
return ret;
}
@ -351,13 +351,13 @@ std::list<MineInfo> Client::miningHistory()
{
std::list<MineInfo> ret;
ReadGuard l(x_miners);
if (m_miners.empty())
ReadGuard l(x_localMiners);
if (m_localMiners.empty())
return ret;
ret = m_miners[0].miningHistory();
for (unsigned i = 1; i < m_miners.size(); ++i)
ret = m_localMiners[0].miningHistory();
for (unsigned i = 1; i < m_localMiners.size(); ++i)
{
auto l = m_miners[i].miningHistory();
auto l = m_localMiners[i].miningHistory();
auto ri = ret.begin();
auto li = l.begin();
for (; ri != ret.end() && li != l.end(); ++ri, ++li)
@ -474,6 +474,22 @@ void Client::inject(bytesConstRef _rlp)
m_tq.attemptImport(_rlp);
}
pair<h256, u256> Client::getWork()
{
Guard l(x_remoteMiner);
{
ReadGuard l(x_stateDB);
m_remoteMiner.update(m_postMine, m_bc);
}
return make_pair(m_remoteMiner.workHash(), m_remoteMiner.difficulty());
}
bool Client::submitNonce(h256 const&_nonce)
{
Guard l(x_remoteMiner);
return m_remoteMiner.submitWork(_nonce);
}
void Client::doWork()
{
// TODO: Use condition variable rather than polling.
@ -481,27 +497,34 @@ void Client::doWork()
cworkin << "WORK";
h256Set changeds;
auto maintainMiner = [&](Miner& m)
{
ReadGuard l(x_miners);
for (auto& m: m_miners)
if (m.isComplete())
if (m.isComplete())
{
cwork << "CHAIN <== postSTATE";
h256s hs;
{
cwork << "CHAIN <== postSTATE";
h256s hs;
{
WriteGuard l(x_stateDB);
hs = m_bc.attemptImport(m.blockData(), m_stateDB);
}
if (hs.size())
{
for (auto h: hs)
appendFromNewBlock(h, changeds);
changeds.insert(ChainChangedFilter);
//changeds.insert(PendingChangedFilter); // if we mined the new block, then we've probably reset the pending transactions.
}
for (auto& m: m_miners)
m.noteStateChange();
WriteGuard l(x_stateDB);
hs = m_bc.attemptImport(m.blockData(), m_stateDB);
}
if (hs.size())
{
for (auto const& h: hs)
appendFromNewBlock(h, changeds);
changeds.insert(ChainChangedFilter);
}
for (auto& m: m_localMiners)
m.noteStateChange();
}
};
{
ReadGuard l(x_localMiners);
for (auto& m: m_localMiners)
maintainMiner(m);
}
{
Guard l(x_remoteMiner);
maintainMiner(m_remoteMiner);
}
// Synchronise state to block chain.
@ -511,7 +534,7 @@ void Client::doWork()
// if there are no checkpoints before our fork) reverting to the genesis block and replaying
// all blocks.
// Resynchronise state with block chain & trans
bool rsm = false;
bool resyncStateNeeded = false;
{
WriteGuard l(x_stateDB);
cwork << "BQ ==> CHAIN ==> STATE";
@ -534,7 +557,7 @@ void Client::doWork()
if (isMining())
cnote << "New block on chain: Restarting mining operation.";
m_postMine = m_preMine;
rsm = true;
resyncStateNeeded = true;
changeds.insert(PendingChangedFilter);
// TODO: Move transactions pending from m_postMine back to transaction queue.
}
@ -550,13 +573,13 @@ void Client::doWork()
if (isMining())
cnote << "Additional transaction ready: Restarting mining operation.";
rsm = true;
resyncStateNeeded = true;
}
}
if (rsm)
if (resyncStateNeeded)
{
ReadGuard l(x_miners);
for (auto& m: m_miners)
ReadGuard l(x_localMiners);
for (auto& m: m_localMiners)
m.noteStateChange();
}

50
libethereum/Client.h

@ -135,6 +135,28 @@ template <class T> T abiOut(bytes const& _data)
return ABIDeserialiser<T>::deserialise(o);
}
class RemoteMiner: public Miner
{
public:
RemoteMiner() {}
void update(State const& _provisional, BlockChain const& _bc) { m_state = _provisional; m_state.commitToMine(_bc); }
h256 workHash() const { return m_state.info().headerHash(IncludeNonce::WithoutNonce); }
u256 const& difficulty() const { return m_state.info().difficulty; }
bool submitWork(h256 const& _nonce) { return (m_isComplete = m_state.completeMine(_nonce)); }
virtual bool isComplete() const override { return m_isComplete; }
virtual bytes const& blockData() const { return m_state.blockData(); }
virtual void noteStateChange() override {}
private:
bool m_isComplete = false;
State m_state;
};
/**
* @brief Main API hub for interfacing with Ethereum.
*/
@ -253,20 +275,26 @@ public:
/// Stops mining and sets the number of mining threads (0 for automatic).
virtual void setMiningThreads(unsigned _threads = 0);
/// Get the effective number of mining threads.
virtual unsigned miningThreads() const { ReadGuard l(x_miners); return m_miners.size(); }
virtual unsigned miningThreads() const { ReadGuard l(x_localMiners); return m_localMiners.size(); }
/// Start mining.
/// NOT thread-safe - call it & stopMining only from a single thread
virtual void startMining() { startWorking(); ReadGuard l(x_miners); for (auto& m: m_miners) m.start(); }
virtual void startMining() { startWorking(); ReadGuard l(x_localMiners); for (auto& m: m_localMiners) m.start(); }
/// Stop mining.
/// NOT thread-safe
virtual void stopMining() { ReadGuard l(x_miners); for (auto& m: m_miners) m.stop(); }
virtual void stopMining() { ReadGuard l(x_localMiners); for (auto& m: m_localMiners) m.stop(); }
/// Are we mining now?
virtual bool isMining() { ReadGuard l(x_miners); return m_miners.size() && m_miners[0].isRunning(); }
virtual bool isMining() { ReadGuard l(x_localMiners); return m_localMiners.size() && m_localMiners[0].isRunning(); }
/// Check the progress of the mining.
virtual MineProgress miningProgress() const;
/// Get and clear the mining history.
std::list<MineInfo> miningHistory();
/// Update to the latest transactions and get hash of the current block to be mined minus the
/// nonce (the 'work hash') and the difficulty to be met.
virtual std::pair<h256, u256> getWork() override;
/// Submit the nonce for the proof-of-work.
virtual bool submitNonce(h256 const&_nonce) override;
// Debug stuff:
DownloadMan const* downloadMan() const;
@ -295,6 +323,7 @@ private:
/// Do some work. Handles blockchain maintenance and mining.
virtual void doWork();
/// Called when Worker is exiting.
virtual void doneWorking();
/// Overrides for being a mining host.
@ -309,24 +338,27 @@ private:
State asOf(unsigned _h) const;
VersionChecker m_vc; ///< Dummy object to check & update the protocol version.
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.
BlockQueue m_bq; ///< Maintains a list of incoming blocks not yet on the blockchain (to be imported).
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.
State m_preMine; ///< The present state of the client.
State m_postMine; ///< The state of the client which we're mining (i.e. it'll have all the rewards added).
std::weak_ptr<EthereumHost> m_host; ///< Our Ethereum Host. Don't do anything if we can't lock.
std::vector<Miner> m_miners;
mutable SharedMutex x_miners;
mutable Mutex x_remoteMiner; ///< The remote miner lock.
RemoteMiner m_remoteMiner; ///< The remote miner.
std::vector<LocalMiner> m_localMiners; ///< The in-process miners.
mutable SharedMutex x_localMiners; ///< The in-process miners lock.
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_forceMining = false; ///< Mine even when there are no transactions pending?
mutable std::mutex m_filterLock;
mutable Mutex m_filterLock;
std::map<h256, InstalledFilter> m_filters;
std::map<unsigned, ClientWatch> m_watches;

5
libethereum/Interface.h

@ -149,6 +149,11 @@ public:
/// Are we mining now?
virtual bool isMining() = 0;
/// Get hash of the current block to be mined minus the nonce (the 'work hash').
virtual std::pair<h256, u256> getWork() = 0;
/// Submit the nonce for the proof-of-work.
virtual bool submitNonce(h256 const&) = 0;
/// Check the progress of the mining.
virtual MineProgress miningProgress() const = 0;

12
libethereum/Miner.cpp

@ -15,8 +15,8 @@
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file Miner.cpp
* @author Alex Leverington <nessence@gmail.com>
* @author Gav Wood <i@gavwood.com>
* @author Giacomo Tazzari
* @date 2014
*/
@ -28,19 +28,21 @@ using namespace std;
using namespace dev;
using namespace dev::eth;
Miner::Miner(MinerHost* _host, unsigned _id):
Miner::~Miner() {}
LocalMiner::LocalMiner(MinerHost* _host, unsigned _id):
Worker("miner-" + toString(_id)),
m_host(_host)
{
}
void Miner::setup(MinerHost* _host, unsigned _id)
void LocalMiner::setup(MinerHost* _host, unsigned _id)
{
m_host = _host;
setName("miner-" + toString(_id));
}
void Miner::doWork()
void LocalMiner::doWork()
{
// Do some mining.
if (m_miningStatus != Waiting && m_miningStatus != Mined)
@ -63,7 +65,7 @@ void Miner::doWork()
if (m_miningStatus == Mining)
{
// Mine for a while.
// Mine for a while.
MineInfo mineInfo = m_mineState.mine(100, m_host->turbo());
{

28
libethereum/Miner.h

@ -63,6 +63,16 @@ public:
virtual bool force() const = 0; ///< @returns true iff the Miner should mine regardless of the number of transactions.
};
class Miner
{
public:
virtual ~Miner();
virtual void noteStateChange() = 0;
virtual bool isComplete() const = 0;
virtual bytes const& blockData() const = 0;
};
/**
* @brief Implements Miner.
* To begin mining, use start() & stop(). noteStateChange() can be used to reset the mining and set up the
@ -75,23 +85,23 @@ public:
* @threadsafe
* @todo Signal Miner to restart once with condition variables.
*/
class Miner: Worker
class LocalMiner: public Miner, Worker
{
public:
/// Null constructor.
Miner(): m_host(nullptr) {}
LocalMiner(): m_host(nullptr) {}
/// Constructor.
Miner(MinerHost* _host, unsigned _id = 0);
LocalMiner(MinerHost* _host, unsigned _id = 0);
/// Move-constructor.
Miner(Miner&& _m): Worker((Worker&&)_m) { std::swap(m_host, _m.m_host); }
LocalMiner(LocalMiner&& _m): Worker((Worker&&)_m) { std::swap(m_host, _m.m_host); }
/// Move-assignment.
Miner& operator=(Miner&& _m) { Worker::operator=((Worker&&)_m); std::swap(m_host, _m.m_host); return *this; }
LocalMiner& operator=(LocalMiner&& _m) { Worker::operator=((Worker&&)_m); std::swap(m_host, _m.m_host); return *this; }
/// Destructor. Stops miner.
~Miner() { stop(); }
~LocalMiner() { stop(); }
/// Setup its basics.
void setup(MinerHost* _host, unsigned _id = 0);
@ -103,16 +113,16 @@ public:
void stop() { stopWorking(); }
/// Call to notify Miner of a state change.
void noteStateChange() { m_miningStatus = Preparing; }
virtual void noteStateChange() override { m_miningStatus = Preparing; }
/// @returns true iff the mining has been start()ed. It may still not be actually mining, depending on the host's turbo() & force().
bool isRunning() { return isWorking(); }
/// @returns true if mining is complete.
bool isComplete() const { return m_miningStatus == Mined; }
virtual bool isComplete() const override { return m_miningStatus == Mined; }
/// @returns the internal State object.
bytes const& blockData() { return m_mineState.blockData(); }
virtual bytes const& blockData() const override { return m_mineState.blockData(); }
/// Check the progress of the mining.
MineProgress miningProgress() const { Guard l(x_mineInfo); return m_mineProgress; }

18
libethereum/State.cpp

@ -774,19 +774,31 @@ MineInfo State::mine(unsigned _msTimeout, bool _turbo)
// Update difficulty according to timestamp.
m_currentBlock.difficulty = m_currentBlock.calculateDifficulty(m_previousBlock);
MineInfo ret;
// TODO: Miner class that keeps dagger between mine calls (or just non-polling mining).
auto ret = m_pow.mine(/*out*/m_currentBlock.nonce, m_currentBlock.headerHash(WithoutNonce), m_currentBlock.difficulty, _msTimeout, true, _turbo);
tie(ret, m_currentBlock.nonce) = m_pow.mine(m_currentBlock.headerHash(WithoutNonce), m_currentBlock.difficulty, _msTimeout, true, _turbo);
if (!ret.completed)
m_currentBytes.clear();
else
{
cnote << "Completed" << m_currentBlock.headerHash(WithoutNonce).abridged() << m_currentBlock.nonce.abridged() << m_currentBlock.difficulty << ProofOfWork::verify(m_currentBlock.headerHash(WithoutNonce), m_currentBlock.nonce, m_currentBlock.difficulty);
}
return ret;
}
bool State::completeMine(h256 const& _nonce)
{
if (!m_pow.verify(m_currentBlock.headerHash(WithoutNonce), _nonce, m_currentBlock.difficulty))
return false;
m_currentBlock.nonce = _nonce;
cnote << "Completed" << m_currentBlock.headerHash(WithoutNonce).abridged() << m_currentBlock.nonce.abridged() << m_currentBlock.difficulty << ProofOfWork::verify(m_currentBlock.headerHash(WithoutNonce), m_currentBlock.nonce, m_currentBlock.difficulty);
completeMine();
return true;
}
void State::completeMine()
{
cdebug << "Completing mine!";

4
libethereum/State.h

@ -113,6 +113,10 @@ public:
/// This may be called multiple times and without issue.
void commitToMine(BlockChain const& _bc);
/// Pass in a solution to the proof-of-work.
/// @returns true iff the given nonce is a proof-of-work for this State's block.
bool completeMine(h256 const& _nonce);
/// Attempt to find valid nonce for block that this state represents.
/// This function is thread-safe. You can safely have other interactions with this object while it is happening.
/// @param _msTimeout Timeout before return in milliseconds.

47
libsolidity/ExpressionCompiler.cpp

@ -867,19 +867,17 @@ unsigned ExpressionCompiler::appendExpressionCopyToMemory(Type const& _expectedT
void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const& _varDecl)
{
FunctionType thisType(_varDecl);
solAssert(thisType.getReturnParameterTypes().size() == 1, "");
TypePointer const& resultType = thisType.getReturnParameterTypes().front();
unsigned sizeOnStack;
FunctionType accessorType(_varDecl);
unsigned length = 0;
TypePointers const& params = thisType.getParameterTypes();
TypePointers const& params = accessorType.getParameterTypes();
// move arguments to memory
for (TypePointer const& param: boost::adaptors::reverse(params))
length += appendTypeConversionAndMoveToMemory(*param, *param, Location(), length);
// retrieve the position of the mapping
// retrieve the position of the variable
m_context << m_context.getStorageLocationOfVariable(_varDecl);
TypePointer returnType = _varDecl.getType();
for (TypePointer const& param: params)
{
@ -888,13 +886,40 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
unsigned argLen = CompilerUtils::getPaddedSize(param->getCalldataEncodedSize());
length -= argLen;
m_context << u256(argLen + 32) << u256(length) << eth::Instruction::SHA3;
returnType = dynamic_cast<MappingType const&>(*returnType).getValueType();
}
m_currentLValue = LValue(m_context, LValue::STORAGE, *resultType);
m_currentLValue.retrieveValue(resultType, Location(), true);
sizeOnStack = resultType->getSizeOnStack();
solAssert(sizeOnStack <= 15, "Stack too deep.");
m_context << eth::dupInstruction(sizeOnStack + 1) << eth::Instruction::JUMP;
unsigned retSizeOnStack = 0;
solAssert(accessorType.getReturnParameterTypes().size() >= 1, "");
if (StructType const* structType = dynamic_cast<StructType const*>(returnType.get()))
{
auto const& names = accessorType.getReturnParameterNames();
auto const& types = accessorType.getReturnParameterTypes();
// struct
for (size_t i = 0; i < names.size(); ++i)
{
m_context << eth::Instruction::DUP1
<< structType->getStorageOffsetOfMember(names[i])
<< eth::Instruction::ADD;
m_currentLValue = LValue(m_context, LValue::STORAGE, *types[i]);
m_currentLValue.retrieveValue(types[i], Location(), true);
solAssert(types[i]->getSizeOnStack() == 1, "Returning struct elements with stack size != 1 not yet implemented.");
m_context << eth::Instruction::SWAP1;
retSizeOnStack += types[i]->getSizeOnStack();
}
m_context << eth::Instruction::POP;
}
else
{
// simple value
solAssert(accessorType.getReturnParameterTypes().size() == 1, "");
m_currentLValue = LValue(m_context, LValue::STORAGE, *returnType);
m_currentLValue.retrieveValue(returnType, Location(), true);
retSizeOnStack = returnType->getSizeOnStack();
}
solAssert(retSizeOnStack <= 15, "Stack too deep.");
m_context << eth::dupInstruction(retSizeOnStack + 1) << eth::Instruction::JUMP;
}
ExpressionCompiler::LValue::LValue(CompilerContext& _compilerContext, LValueType _type, Type const& _dataType,

27
libsolidity/Types.cpp

@ -643,22 +643,31 @@ FunctionType::FunctionType(VariableDeclaration const& _varDecl):
{
TypePointers params;
vector<string> paramNames;
TypePointers retParams;
vector<string> retParamNames;
TypePointer varDeclType = _varDecl.getType();
auto mappingType = dynamic_cast<MappingType const*>(varDeclType.get());
auto returnType = varDeclType;
auto returnType = _varDecl.getType();
while (mappingType != nullptr)
while (auto mappingType = dynamic_cast<MappingType const*>(returnType.get()))
{
params.push_back(mappingType->getKeyType());
paramNames.push_back("");
returnType = mappingType->getValueType();
mappingType = dynamic_cast<MappingType const*>(mappingType->getValueType().get());
}
retParams.push_back(returnType);
retParamNames.push_back("");
TypePointers retParams;
vector<string> retParamNames;
if (auto structType = dynamic_cast<StructType const*>(returnType.get()))
{
for (pair<string, TypePointer> const& member: structType->getMembers())
if (member.second->canLiveOutsideStorage())
{
retParamNames.push_back(member.first);
retParams.push_back(member.second);
}
}
else
{
retParams.push_back(returnType);
retParamNames.push_back("");
}
swap(params, m_parameterTypes);
swap(paramNames, m_parameterNames);

12
libweb3jsonrpc/WebThreeStubServer.h

@ -44,13 +44,13 @@ public:
WebThreeStubServer(jsonrpc::AbstractServerConnector& _conn, dev::WebThreeDirect& _web3, std::vector<dev::KeyPair> const& _accounts);
private:
dev::eth::Interface* client() override;
std::shared_ptr<dev::shh::Interface> face() override;
dev::WebThreeNetworkFace* network() override;
dev::WebThreeStubDatabaseFace* db() override;
virtual dev::eth::Interface* client() override;
virtual std::shared_ptr<dev::shh::Interface> face() override;
virtual dev::WebThreeNetworkFace* network() override;
virtual dev::WebThreeStubDatabaseFace* db() override;
std::string get(std::string const& _name, std::string const& _key) override;
void put(std::string const& _name, std::string const& _key, std::string const& _value) override;
virtual std::string get(std::string const& _name, std::string const& _key) override;
virtual void put(std::string const& _name, std::string const& _key, std::string const& _value) override;
private:
dev::WebThreeDirect& m_web3;

14
libweb3jsonrpc/WebThreeStubServerBase.cpp

@ -428,6 +428,20 @@ int WebThreeStubServerBase::eth_newFilterString(std::string const& _filter)
return ret;
}
Json::Value WebThreeStubServerBase::eth_getWork()
{
Json::Value ret(Json::arrayValue);
auto r = client()->getWork();
ret.append(toJS(r.first));
ret.append(toJS(r.second));
return ret;
}
bool WebThreeStubServerBase::eth_submitWork(std::string const& _nonce)
{
return client()->submitNonce(jsToFixed<32>(_nonce));
}
std::string WebThreeStubServerBase::shh_newGroup(std::string const& _id, std::string const& _who)
{
(void)_id;

3
libweb3jsonrpc/WebThreeStubServerBase.h

@ -103,6 +103,9 @@ public:
virtual Json::Value eth_uncleByNumber(int const& _number, int const& _i);
virtual bool eth_uninstallFilter(int const& _id);
virtual Json::Value eth_getWork();
virtual bool eth_submitWork(std::string const& _nonce);
virtual std::string db_get(std::string const& _name, std::string const& _key);
virtual std::string db_getString(std::string const& _name, std::string const& _key);
virtual bool db_put(std::string const& _name, std::string const& _key, std::string const& _value);

12
libweb3jsonrpc/abstractwebthreestubserver.h

@ -49,6 +49,8 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServer<AbstractWebThr
this->bindAndAddMethod(new jsonrpc::Procedure("eth_changed", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_changedI);
this->bindAndAddMethod(new jsonrpc::Procedure("eth_filterLogs", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_filterLogsI);
this->bindAndAddMethod(new jsonrpc::Procedure("eth_logs", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::eth_logsI);
this->bindAndAddMethod(new jsonrpc::Procedure("eth_getWork", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, NULL), &AbstractWebThreeStubServer::eth_getWorkI);
this->bindAndAddMethod(new jsonrpc::Procedure("eth_submitWork", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_submitWorkI);
this->bindAndAddMethod(new jsonrpc::Procedure("db_put", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING,"param3",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::db_putI);
this->bindAndAddMethod(new jsonrpc::Procedure("db_get", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::db_getI);
this->bindAndAddMethod(new jsonrpc::Procedure("db_putString", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING,"param3",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::db_putStringI);
@ -211,6 +213,14 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServer<AbstractWebThr
{
response = this->eth_logs(request[0u]);
}
inline virtual void eth_getWorkI(const Json::Value &request, Json::Value &response)
{
response = this->eth_getWork();
}
inline virtual void eth_submitWorkI(const Json::Value &request, Json::Value &response)
{
response = this->eth_submitWork(request[0u].asString());
}
inline virtual void db_putI(const Json::Value &request, Json::Value &response)
{
response = this->db_put(request[0u].asString(), request[1u].asString(), request[2u].asString());
@ -296,6 +306,8 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServer<AbstractWebThr
virtual Json::Value eth_changed(const int& param1) = 0;
virtual Json::Value eth_filterLogs(const int& param1) = 0;
virtual Json::Value eth_logs(const Json::Value& param1) = 0;
virtual Json::Value eth_getWork() = 0;
virtual bool eth_submitWork(const std::string& param1) = 0;
virtual bool db_put(const std::string& param1, const std::string& param2, const std::string& param3) = 0;
virtual std::string db_get(const std::string& param1, const std::string& param2) = 0;
virtual bool db_putString(const std::string& param1, const std::string& param2, const std::string& param3) = 0;

4
libweb3jsonrpc/spec.json

@ -36,7 +36,6 @@
{ "name": "eth_solidity", "params": [""], "order": [], "returns": ""},
{ "name": "eth_serpent", "params": [""], "order": [], "returns": ""},
{ "name": "eth_newFilter", "params": [{}], "order": [], "returns": 0},
{ "name": "eth_newFilterString", "params": [""], "order": [], "returns": 0},
{ "name": "eth_uninstallFilter", "params": [0], "order": [], "returns": true},
@ -44,6 +43,9 @@
{ "name": "eth_filterLogs", "params": [0], "order": [], "returns": []},
{ "name": "eth_logs", "params": [{}], "order": [], "returns": []},
{ "name": "eth_getWork", "params": [], "order": [], "returns": []},
{ "name": "eth_submitWork", "params": [""], "order": [], "returns": true},
{ "name": "db_put", "params": ["", "", ""], "order": [], "returns": true},
{ "name": "db_get", "params": ["", ""], "order": [], "returns": ""},
{ "name": "db_putString", "params": ["", "", ""], "order": [], "returns": true},

2
mix/MixClient.h

@ -86,6 +86,8 @@ public:
void stopMining() override;
bool isMining() override;
eth::MineProgress miningProgress() const override;
std::pair<h256, u256> getWork() override { return std::pair<h256, u256>(); }
bool submitNonce(h256 const&) override { return false; }
private:
void executeTransaction(dev::eth::Transaction const& _t, eth::State& _state);

18
test/SolidityEndToEndTest.cpp

@ -959,6 +959,24 @@ BOOST_AUTO_TEST_CASE(complex_accessors)
BOOST_CHECK(callContractFunction("to_multiple_map(uint256,uint256)", 42, 23) == encodeArgs(31));
}
BOOST_AUTO_TEST_CASE(struct_accessor)
{
char const* sourceCode = R"(
contract test {
struct Data { uint a; uint8 b; mapping(uint => uint) c; bool d; }
mapping(uint => Data) public data;
function test() {
data[7].a = 1;
data[7].b = 2;
data[7].c[0] = 3;
data[7].d = true;
}
}
)";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("data(uint256)", 7) == encodeArgs(1, 2, true));
}
BOOST_AUTO_TEST_CASE(balance)
{
char const* sourceCode = "contract test {\n"

Loading…
Cancel
Save