diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6e585fc42..27bf9d5e2 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -25,4 +25,5 @@ endif ()
add_subdirectory(libethereum)
add_subdirectory(test)
+#add_subdirectory(eth)
diff --git a/eth/CMakeLists.txt b/eth/CMakeLists.txt
new file mode 100644
index 000000000..2bb2d56e1
--- /dev/null
+++ b/eth/CMakeLists.txt
@@ -0,0 +1,13 @@
+cmake_policy(SET CMP0015 NEW)
+
+aux_source_directory(. SRC_LIST)
+include_directories(../../secp256k1/include)
+include_directories(../libethereum)
+link_directories(../libethereum)
+link_directories(../../secp256k1)
+
+add_executable(eth ${SRC_LIST})
+
+target_link_libraries(eth secp256k1)
+target_link_libraries(eth ethereum)
+target_link_libraries(eth gmp)
diff --git a/eth/main.cpp b/eth/main.cpp
new file mode 100644
index 000000000..e31ab05ea
--- /dev/null
+++ b/eth/main.cpp
@@ -0,0 +1,76 @@
+/*
+ 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.
+
+ Foobar 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 Foobar. If not, see .
+*/
+/** @file main.cpp
+ * @author Gav Wood
+ * @date 2014
+ * Ethereum client.
+ */
+
+#include "PeerNetwork.h"
+#include "BlockChain.h"
+#include "State.h"
+using namespace std;
+using namespace eth;
+
+int main()
+{
+ // Our address.
+ Address us; // TODO: should be loaded from config file/set at command-line.
+
+ BlockChain bc; // TODO: Implement - should look for block database.
+
+ State s(us);
+// s.restore(); // TODO: Implement - key optimisation.
+
+ TransactionQueue tq; // TODO: Implement.
+
+ // Synchronise the state according to the block chain - i.e. replay all transactions, in order. Will take a while if the state isn't restored.
+ s.sync(bc, tq);
+
+ PeerNetwork net; // TODO: Implement - should run in background and send us events when blocks found and allow us to send blocks as required.
+ while (true)
+ {
+ // Process network events.
+ net.process();
+
+ // Synchronise block chain with network.
+ net.sync(bc, tq);
+
+ // Synchronise state to block chain.
+ // This should remove any transactions on our queue that are included in the block chain.
+ s.sync(bc, tq); // Resynchronise state with block chain & trans
+
+ if (s.mine(100))
+ {
+ // Mined block
+ bytes b = s.blockData();
+ bc.import(b);
+ }
+ }
+
+ return 0;
+}
+
+/*
+while (net.incomingTransaction())
+{
+ bytes const& tx = net.incomingTransaction();
+ s.execute(tx);
+ net.popIncomingTransaction();
+}
+
+*/
diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp
new file mode 100644
index 000000000..0e1fc3d6d
--- /dev/null
+++ b/libethereum/BlockChain.cpp
@@ -0,0 +1,14 @@
+#include "Common.h"
+#include "BlockChain.h"
+using namespace std;
+using namespace eth;
+
+BlockChain::BlockChain()
+{
+}
+
+BlockChain::~BlockChain()
+{
+}
+
+
diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h
new file mode 100644
index 000000000..bb568a1e8
--- /dev/null
+++ b/libethereum/BlockChain.h
@@ -0,0 +1,24 @@
+#pragma once
+
+#include "Common.h"
+
+namespace eth
+{
+
+/**
+ * @brief Models the blockchain database.
+ */
+class BlockChain
+{
+public:
+ BlockChain();
+ ~BlockChain();
+
+ void import(bytes const& _block) {}
+
+private:
+};
+
+}
+
+
diff --git a/libethereum/PeerNetwork.cpp b/libethereum/PeerNetwork.cpp
new file mode 100644
index 000000000..3d714a2da
--- /dev/null
+++ b/libethereum/PeerNetwork.cpp
@@ -0,0 +1,31 @@
+#include "Common.h"
+#include "PeerNetwork.h"
+using namespace std;
+using namespace eth;
+
+PeerNetwork::PeerNetwork()
+{
+}
+
+PeerNetwork::~PeerNetwork()
+{
+}
+
+void PeerNetwork::process()
+{
+}
+
+void PeerNetwork::sync(BlockChain& _bc, TransactionQueue const&)
+{
+/* while (incomingBlock())
+ {
+ // import new block
+ bytes const& block = net.incomingBlock();
+ bc.import(block);
+ net.popIncomingBlock();
+
+ // check block chain and make longest given all available blocks.
+ bc.rejig();
+ }*/
+}
+
diff --git a/libethereum/PeerNetwork.h b/libethereum/PeerNetwork.h
new file mode 100644
index 000000000..894cc6db5
--- /dev/null
+++ b/libethereum/PeerNetwork.h
@@ -0,0 +1,37 @@
+#pragma once
+
+#include "Common.h"
+
+namespace eth
+{
+
+class BlockChain;
+class TransactionQueue;
+
+static const bytes NullBytes;
+
+class PeerNetwork
+{
+public:
+ PeerNetwork();
+ ~PeerNetwork();
+
+ /// Conduct I/O, polling, syncing, whatever.
+ /// Ideally all time-consuming I/O is done in a background thread, but you get this call every 100ms or so anyway.
+ void process();
+
+ /// Sync with the BlockChain. It might contain one of our mined blocks, we might have new candidates from the network.
+ void sync(BlockChain& _bc, TransactionQueue const&);
+
+ /// Get an incoming transaction from the queue. @returns bytes() if nothing waiting.
+ bytes const& incomingTransaction() { return NullBytes; }
+
+ /// Remove incoming transaction from the queue. Make sure you've finished with the data from any previous incomingTransaction() calls.
+ void popIncomingTransaction() {}
+
+private:
+};
+
+}
+
+
diff --git a/libethereum/State.cpp b/libethereum/State.cpp
index a3da5d066..693c45b9b 100644
--- a/libethereum/State.cpp
+++ b/libethereum/State.cpp
@@ -118,7 +118,7 @@ void State::execute(Transaction const& _t, Address _sender)
if (_t.receiveAddress)
{
- assert(subBalance(_sender, _t.value + _t.fee));
+ subBalance(_sender, _t.value + _t.fee);
addBalance(_t.receiveAddress, _t.value);
addBalance(m_minerAddress, _t.fee);
@@ -141,7 +141,7 @@ void State::execute(Transaction const& _t, Address _sender)
auto& mem = m_current[newAddress].memory();
for (uint i = 0; i < _t.data.size(); ++i)
mem[i] = _t.data[i];
- assert(subBalance(_sender, _t.value + _t.fee));
+ subBalance(_sender, _t.value + _t.fee);
addBalance(newAddress, _t.value);
addBalance(m_minerAddress, _t.fee);
}
diff --git a/libethereum/State.h b/libethereum/State.h
index c577e9bd6..f6d8778d2 100644
--- a/libethereum/State.h
+++ b/libethereum/State.h
@@ -34,6 +34,21 @@
namespace eth
{
+class BlockChain;
+
+// TODO: Repot.
+/**
+ * @brief A queue of Transactions, each stored as RLP.
+ */
+class TransactionQueue
+{
+public:
+ void sync(BlockChain const& _bc) {}
+
+private:
+ std::vector m_data;
+};
+
/**
* @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).
@@ -49,30 +64,47 @@ public:
/// Verify a given block.
bool verify(bytes const& _block, uint _number = 0);
+ /// Attempt to find valid nonce for block that this state represents.
+ /// @param _msTimeout Timeout before return in milliseconds.
+ /// @returns true if it got lucky.
+ bool mine(uint _msTimeout = 1000) const { (void)_msTimeout; return false; }
+
+ /// Get the complete current block, including valid nonce.
+ bytes blockData() const { return bytes(); }
+
+ /// Sync our state with the block chain.
+ /// This basically involves wiping ourselves if we've been superceded and rebuilding from the transaction queue.
+ void sync(BlockChain const& _bc, TransactionQueue const& _tq) {}
+
/// Execute a given transaction.
bool execute(bytes const& _rlp) { try { Transaction t(_rlp); execute(t, t.sender()); } catch (...) { return false; } }
/// Check if the address is a valid normal (non-contract) account address.
bool isNormalAddress(Address _address) const;
+
/// Check if the address is a valid contract's address.
bool isContractAddress(Address _address) const;
/// Get an account's balance.
+ /// @returns 0 if the address has never been used.
u256 balance(Address _id) const;
/// Add some amount to balance.
+ /// Will initialise the address if it has never been used.
void addBalance(Address _id, u256 _amount);
/** Subtract some amount from balance.
- * @throws NotEnoughCash if balance of @a _id is less than @a _value.
+ * @throws NotEnoughCash if balance of @a _id is less than @a _value (or has never been used).
* @note We use bigint here as we don't want any accidental problems with negative numbers.
*/
void subBalance(Address _id, bigint _value);
/// Get the value of a memory position of a contract.
+ /// @returns 0 if no contract exists at that address.
u256 contractMemory(Address _contract, u256 _memory) const;
/// Get the number of transactions a particular address has sent (used for the transaction nonce).
+ /// @returns 0 if the address has never been used.
u256 transactionsFrom(Address _address) const;
private:
@@ -93,6 +125,8 @@ private:
// TODO: std::hash and then move to unordered_map.
// Will need to sort on hash construction.
std::map m_current; ///< The current state. We work with a C++ hash map rather than a Trie.
+ std::vector m_transactions; ///< The current list of transactions that we've included in the state.
+
BlockInfo m_previousBlock; ///< The previous block's information.
BlockInfo m_currentBlock; ///< The current block's information.