Browse Source

Various fixes.

cl-refactor
Gav Wood 11 years ago
parent
commit
4347cfc4fc
  1. 1
      CMakeLists.txt
  2. 2
      eth/CMakeLists.txt
  3. 2
      eth/main.cpp
  4. 14
      libethereum/BlockChain.cpp
  5. 2
      libethereum/BlockChain.h
  6. 2
      libethereum/BlockInfo.cpp
  7. 2
      libethereum/CMakeLists.txt
  8. 2
      libethereum/Common.cpp
  9. 29
      libethereum/Common.h
  10. 84
      libethereum/State.cpp
  11. 9
      libethereum/State.h
  12. 9
      libethereum/Transaction.cpp
  13. 2
      libethereum/Transaction.h
  14. 8
      libethereum/TrieDB.h
  15. 2
      test/CMakeLists.txt
  16. 17
      test/crypto.cpp
  17. 2
      test/main.cpp
  18. 31
      test/state.cpp

1
CMakeLists.txt

@ -26,4 +26,3 @@ endif ()
add_subdirectory(libethereum)
add_subdirectory(test)
add_subdirectory(eth)

2
eth/CMakeLists.txt

@ -18,3 +18,5 @@ target_link_libraries(eth leveldb)
target_link_libraries(eth secp256k1)
target_link_libraries(eth cryptopp)
target_link_libraries(eth gmp)
target_link_libraries(eth boost_system)
target_link_libraries(eth boost_filesystem)

2
eth/main.cpp

@ -30,7 +30,7 @@ int main()
{
// Our address.
h256 privkey = sha3("123");
Address us = toPublic(privkey); // TODO: should be loaded from config file/set at command-line.
Address us = toAddress(privkey); // TODO: should be loaded from config file/set at command-line.
BlockChain bc; // Maintains block database.
TransactionQueue tq; // Maintains list of incoming transactions not yet on the block chain.

14
libethereum/BlockChain.cpp

@ -19,6 +19,7 @@
* @date 2014
*/
#include <boost/filesystem.hpp>
#include "Common.h"
#include "RLP.h"
#include "Exceptions.h"
@ -29,10 +30,17 @@
using namespace std;
using namespace eth;
BlockChain::BlockChain()
BlockChain::BlockChain(std::string _path, bool _killExisting)
{
if (_path.empty())
_path = string(getenv("HOME")) + "/.ethereum";
boost::filesystem::create_directory(_path);
if (_killExisting)
boost::filesystem::remove_all(_path + "/blocks");
ldb::Options o;
auto s = ldb::DB::Open(o, "blockchain", &m_db);
o.create_if_missing = true;
auto s = ldb::DB::Open(o, _path + "/blocks", &m_db);
// Initialise with the genesis as the last block on the longest chain.
m_lastBlockHash = m_genesisHash = BlockInfo::genesis().hash;
@ -91,7 +99,7 @@ void BlockChain::import(bytes const& _block)
BlockInfo biGrandParent;
if (it->second.number)
biGrandParent.populate(block(it->second.parent));
u256 td = it->second.totalDifficulty + s.playback(&_block, bi, biParent, biGrandParent);
u256 td = it->second.totalDifficulty + s.playback(&_block, bi, biParent, biGrandParent, true);
// All ok - insert into DB
m_details[newHash] = BlockDetails{(uint)it->second.number + 1, bi.parentHash, td};

2
libethereum/BlockChain.h

@ -44,7 +44,7 @@ static const h256s NullH256s;
class BlockChain
{
public:
BlockChain();
BlockChain(std::string _path = std::string(), bool _killExisting = false);
~BlockChain();
/// (Potentially) renders invalid existing bytesConstRef returned by lastBlock.

2
libethereum/BlockInfo.cpp

@ -121,6 +121,6 @@ void BlockInfo::verifyParent(BlockInfo const& _parent) const
throw InvalidDifficulty();
// Check timestamp is after previous timestamp.
if (parentHash && _parent.timestamp <= _parent.timestamp)
if (parentHash && _parent.timestamp >= timestamp)
throw InvalidTimestamp();
}

2
libethereum/CMakeLists.txt

@ -13,3 +13,5 @@ target_link_libraries(ethereum secp256k1)
target_link_libraries(ethereum leveldb)
target_link_libraries(ethereum cryptopp)
target_link_libraries(ethereum gmp)
target_link_libraries(ethereum boost_system)
target_link_libraries(ethereum boost_filesystem)

2
libethereum/Common.cpp

@ -144,7 +144,7 @@ h256 eth::sha3(bytesConstRef _input)
return ret;
}
Address eth::toPublic(PrivateKey _private)
Address eth::toAddress(Secret _private)
{
secp256k1_start();

29
libethereum/Common.h

@ -83,6 +83,14 @@ public:
bool operator!=(FixedHash const& _c) const { return m_data != _c.m_data; }
bool operator<(FixedHash const& _c) const { return m_data < _c.m_data; }
FixedHash& operator^=(FixedHash const& _c) { for (auto i = 0; i < N; ++i) m_data[i] ^= _c.m_data[i]; return *this; }
FixedHash operator^(FixedHash const& _c) const { return FixedHash(*this) ^= _c; }
FixedHash& operator|=(FixedHash const& _c) { for (auto i = 0; i < N; ++i) m_data[i] |= _c.m_data[i]; return *this; }
FixedHash operator|(FixedHash const& _c) const { return FixedHash(*this) |= _c; }
FixedHash& operator&=(FixedHash const& _c) { for (auto i = 0; i < N; ++i) m_data[i] &= _c.m_data[i]; return *this; }
FixedHash operator&(FixedHash const& _c) const { return FixedHash(*this) &= _c; }
FixedHash& operator~() { for (auto i = 0; i < N; ++i) m_data[i] = ~m_data[i]; return *this; }
byte& operator[](unsigned _i) { return m_data[_i]; }
byte operator[](unsigned _i) const { return m_data[_i]; }
@ -98,8 +106,9 @@ private:
template <unsigned N>
inline std::ostream& operator<<(std::ostream& _out, FixedHash<N> const& _h)
{
_out << std::noshowbase << std::hex << std::setfill('0');
for (unsigned i = 0; i < N; ++i)
_out << std::hex << std::setfill('0') << std::setw(2) << (int)_h[i];
_out << std::setw(2) << (int)_h[i];
return _out;
}
@ -110,7 +119,7 @@ using h160s = std::vector<h160>;
using h256Set = std::set<h256>;
using h160Set = std::set<h160>;
using PrivateKey = h256;
using Secret = h256;
using Address = h160;
using Addresses = h160s;
@ -317,6 +326,20 @@ inline h256 sha3(std::string const& _input) { return sha3(bytesConstRef(_input))
/// Convert a private key into the public key equivalent.
/// @returns 0 if it's not a valid private key.
Address toPublic(h256 _private);
Address toAddress(h256 _private);
class KeyPair
{
public:
KeyPair() {}
KeyPair(Secret _k): m_secret(_k), m_address(toAddress(_k)) {}
Secret secret() const { return m_secret; }
Address address() const { return m_address; }
private:
Secret m_secret;
Address m_address;
};
}

84
libethereum/State.cpp

@ -44,30 +44,35 @@
using namespace std;
using namespace eth;
u256 const State::c_stepFee = 0;
u256 const State::c_dataFee = 0;
u256 const State::c_memoryFee = 0;
u256 const State::c_extroFee = 0;
u256 const State::c_cryptoFee = 0;
u256 const State::c_newContractFee = 0;
u256 const State::c_stepFee = 10000;
u256 const State::c_dataFee = 20000;
u256 const State::c_memoryFee = 30000;
u256 const State::c_extroFee = 40000;
u256 const State::c_cryptoFee = 50000;
u256 const State::c_newContractFee = 60000;
u256 const State::c_txFee = 0;
u256 const State::c_blockReward = 0;
u256 const State::c_blockReward = 1000000000;
State::State(Address _coinbaseAddress): m_state(&m_db), m_ourAddress(_coinbaseAddress)
State::State(Address _coinbaseAddress, std::string _path, bool _killExisting): m_state(&m_db), m_ourAddress(_coinbaseAddress)
{
secp256k1_start();
m_previousBlock = BlockInfo::genesis();
m_currentBlock.coinbaseAddress = m_ourAddress;
boost::filesystem::create_directory(string(getenv("HOME")) + "/.ethereum/");
if (_path.empty())
_path = string(getenv("HOME")) + "/.ethereum";
boost::filesystem::create_directory(_path);
if (_killExisting)
boost::filesystem::remove_all(_path + "/state");
ldb::Options o;
o.create_if_missing = true;
ldb::DB* db = nullptr;
ldb::DB::Open(o, string(getenv("HOME")) + "/.ethereum/state", &db);
ldb::DB::Open(o, _path + "/state", &db);
m_db.setDB(db);
m_state.init();
m_state.setRoot(m_currentBlock.stateRoot);
m_previousBlock = BlockInfo::genesis();
resetCurrent();
}
void State::ensureCached(Address _a, bool _requireMemory) const
@ -79,7 +84,9 @@ void State::ensureCached(Address _a, bool _requireMemory) const
string stateBack = m_state.at(_a);
RLP state(stateBack);
AddressState s;
if (state.itemCount() == 2)
if (state.isNull())
s = AddressState(0, 0);
else if (state.itemCount() == 2)
s = AddressState(state[0].toInt<u256>(), state[1].toInt<u256>());
else
s = AddressState(state[0].toInt<u256>(), state[1].toInt<u256>(), state[2].toHash<h256>());
@ -104,7 +111,7 @@ void State::commit()
m_state.remove(i.first);
else
{
RLPStream s;
RLPStream s(i.second.type() == AddressType::Contract ? 3 : 2);
s << i.second.balance() << i.second.nonce();
if (i.second.type() == AddressType::Contract)
{
@ -114,7 +121,7 @@ void State::commit()
memdb.init();
for (auto const& j: i.second.memory())
if (j.second)
memdb.insert(j.first, rlp(j.second)); // TODO: CHECK: check this isn't RLP or compact
memdb.insert(j.first, rlp(j.second));
s << memdb.root();
}
else
@ -179,7 +186,7 @@ void State::sync(BlockChain const& _bc, h256 _block)
// Iterate through in reverse, playing back each of the blocks.
for (auto it = next(l.cbegin()); it != l.cend(); ++it)
playback(_bc.block(*it));
playback(_bc.block(*it), true);
m_currentNumber = _bc.details(_bc.currentHash()).number + 1;
resetCurrent();
@ -193,6 +200,8 @@ void State::resetCurrent()
m_currentBlock = BlockInfo();
m_currentBlock.coinbaseAddress = m_ourAddress;
m_currentBlock.stateRoot = m_previousBlock.stateRoot;
m_currentBlock.parentHash = m_previousBlock.hash;
m_state.setRoot(m_currentBlock.stateRoot);
}
void State::sync(TransactionQueue& _tq)
@ -224,13 +233,13 @@ void State::sync(TransactionQueue& _tq)
}
}
u256 State::playback(bytesConstRef _block)
u256 State::playback(bytesConstRef _block, bool _fullCommit)
{
try
{
m_currentBlock.populate(_block);
m_currentBlock.verifyInternals(_block);
return playback(_block, BlockInfo());
return playback(_block, BlockInfo(), _fullCommit);
}
catch (...)
{
@ -240,14 +249,14 @@ u256 State::playback(bytesConstRef _block)
}
}
u256 State::playback(bytesConstRef _block, BlockInfo const& _bi, BlockInfo const& _parent, BlockInfo const& _grandParent)
u256 State::playback(bytesConstRef _block, BlockInfo const& _bi, BlockInfo const& _parent, BlockInfo const& _grandParent, bool _fullCommit)
{
m_currentBlock = _bi;
m_previousBlock = _parent;
return playback(_block, _grandParent);
return playback(_block, _grandParent, _fullCommit);
}
u256 State::playback(bytesConstRef _block, BlockInfo const& _grandParent)
u256 State::playback(bytesConstRef _block, BlockInfo const& _grandParent, bool _fullCommit)
{
if (m_currentBlock.parentHash != m_previousBlock.hash)
throw InvalidParentHash();
@ -279,16 +288,27 @@ u256 State::playback(bytesConstRef _block, BlockInfo const& _grandParent)
// Hash the state trie and check against the state_root hash in m_currentBlock.
if (m_currentBlock.stateRoot != rootHash())
{
cout << m_state;
cout << TrieDB<Address, Overlay>(&m_db, m_state.root());
cout << TrieDB<Address, Overlay>(&m_db, m_currentBlock.stateRoot) << endl;
// Rollback the trie.
m_db.rollback();
throw InvalidStateRoot();
}
// Commit the new trie to disk.
m_db.commit();
if (_fullCommit)
{
// Commit the new trie to disk.
m_db.commit();
m_previousBlock = m_currentBlock;
resetCurrent();
m_previousBlock = m_currentBlock;
resetCurrent();
}
else
{
m_db.rollback();
resetCurrent();
}
return tdIncrease;
}
@ -298,17 +318,25 @@ u256 State::playback(bytesConstRef _block, BlockInfo const& _grandParent)
void State::commitToMine(BlockChain const& _bc)
{
RLPStream uncles;
Addresses uncleAddresses;
if (m_previousBlock != BlockInfo::genesis())
{
// Find uncles if we're not a direct child of the genesis.
auto us = _bc.details(m_previousBlock.parentHash).children;
uncles.appendList(us.size());
for (auto const& u: us)
BlockInfo(_bc.block(u)).fillStream(uncles, true);
{
BlockInfo ubi(_bc.block(u));
ubi.fillStream(uncles, true);
uncleAddresses.push_back(ubi.coinbaseAddress);
}
}
else
uncles.appendList(0);
applyRewards(uncleAddresses);
RLPStream txs(m_transactions.size());
for (auto const& i: m_transactions)
i.second.fillStream(txs);
@ -321,7 +349,9 @@ void State::commitToMine(BlockChain const& _bc)
// Commit any and all changes to the trie that are in the cache, then update the state root accordingly.
commit();
cout << m_state;
m_currentBlock.stateRoot = m_state.root();
m_currentBlock.parentHash = m_previousBlock.hash;
}
bool State::mine(uint _msTimeout)

9
libethereum/State.h

@ -49,7 +49,7 @@ class State
{
public:
/// Construct state object.
explicit State(Address _coinbaseAddress);
explicit State(Address _coinbaseAddress, std::string _path = std::string(), bool _killExisting = false);
/// Cancels transactions and rolls back the state to the end of the previous block.
/// @warning This will only work for on any transactions after you called the last commitToMine().
@ -60,6 +60,7 @@ public:
/// Commits all transactions into the trie, compiles uncles and transactions list, applies all
/// rewards and populates the current block header with the appropriate hashes.
/// The only thing left to do after this is to actually mine().
/// @warning Only call this once!
void commitToMine(BlockChain const& _bc);
/// Attempt to find valid nonce for block that this state represents.
@ -127,7 +128,7 @@ public:
/// @returns the additional total difficulty.
/// If the _grandParent is passed, it will check the validity of each of the uncles.
/// This might throw.
u256 playback(bytesConstRef _block, BlockInfo const& _bi, BlockInfo const& _parent, BlockInfo const& _grandParent);
u256 playback(bytesConstRef _block, BlockInfo const& _bi, BlockInfo const& _parent, BlockInfo const& _grandParent, bool _fullCommit);
private:
/// Fee-adder on destruction RAII class.
@ -146,11 +147,11 @@ private:
/// Execute the given block on our previous block. This will set up m_currentBlock first, then call the other playback().
/// Any failure will be critical.
u256 playback(bytesConstRef _block);
u256 playback(bytesConstRef _block, bool _fullCommit);
/// Execute the given block, assuming it corresponds to m_currentBlock. If _grandParent is passed, it will be used to check the uncles.
/// Throws on failure.
u256 playback(bytesConstRef _block, BlockInfo const& _grandParent);
u256 playback(bytesConstRef _block, BlockInfo const& _grandParent, bool _fullCommit);
/// Execute a decoded transaction object, given a sender.
/// This will append @a _t to the transaction list and change the state accordingly.

9
libethereum/Transaction.cpp

@ -54,13 +54,16 @@ Address Transaction::sender() const
return right160(eth::sha3(bytesConstRef(&(pubkey[1]), 64)));
}
void Transaction::sign(PrivateKey _priv)
void Transaction::sign(Secret _priv)
{
int v = 0;
secp256k1_start();
h256 msg = sha3(false);
byte sig[64];
if (!secp256k1_ecdsa_sign_compact(msg.data(), 32, sig, _priv.data(), kFromMessage(msg, _priv).data(), &v))
h256 nonce = kFromMessage(msg, _priv);
if (!secp256k1_ecdsa_sign_compact(msg.data(), 32, sig, _priv.data(), nonce.data(), &v))
throw InvalidSignature();
vrs.v = (byte)(v + 27);
@ -91,6 +94,6 @@ h256 Transaction::kFromMessage(h256 _msg, h256 _priv)
v = hmac.new(k, v, hashlib.sha256).digest()
return decode(hmac.new(k, v, hashlib.sha256).digest(),256)
*/
return h256();
return _msg ^ _priv;
}

2
libethereum/Transaction.h

@ -49,7 +49,7 @@ struct Transaction
Signature vrs;
Address sender() const;
void sign(PrivateKey _priv);
void sign(Secret _priv);
static h256 kFromMessage(h256 _msg, h256 _priv);

8
libethereum/TrieDB.h

@ -95,7 +95,7 @@ private:
/**
* @brief Merkle Patricia Tree "Trie": a modifed base-16 Radix tree.
* This version uses an LDB backend - TODO: split off m_db & m_over into opaque key/value map layer and allow caching & testing without DB.
* This version uses an LDB backend
*/
template <class DB>
class GenericTrieDB
@ -365,8 +365,8 @@ public:
{
auto p = Super::at();
value_type ret;
assert(p.first.size() == sizeof(ret));
memcpy(&ret.first, p.first.data(), sizeof(ret));
assert(p.first.size() == sizeof(KeyType));
memcpy(&ret.first, p.first.data(), sizeof(KeyType));
ret.second = p.second;
return ret;
}
@ -415,7 +415,7 @@ template <class DB> std::string GenericTrieDB<DB>::at(bytesConstRef _key) const
template <class DB> std::string GenericTrieDB<DB>::atAux(RLP const& _here, NibbleSlice _key) const
{
if (_here.isEmpty())
if (_here.isEmpty() || _here.isNull())
// not found.
return std::string();
assert(_here.isList() && (_here.itemCount() == 2 || _here.itemCount() == 17));

2
test/CMakeLists.txt

@ -17,3 +17,5 @@ target_link_libraries(testeth ethereum)
target_link_libraries(testeth cryptopp)
target_link_libraries(testeth secp256k1)
target_link_libraries(testeth gmp)
target_link_libraries(testeth boost_system)
target_link_libraries(testeth boost_filesystem)

17
test/crypto.cpp

@ -34,8 +34,16 @@ int cryptoTest()
bytes tx = fromUserHex("88005401010101010101010101010101010101010101011f0de0b6b3a76400001ce8d4a5100080181c373130a009ba1f10285d4e659568bfcfec85067855c5a3c150100815dad4ef98fd37cf0593828c89db94bd6c64e210a32ef8956eaa81ea9307194996a3b879441f5d");
cout << "TX: " << RLP(tx) << endl;
Transaction t(tx);
cout << "SENDER: " << hex << t.sender() << endl;
Transaction t2(tx);
cout << "SENDER: " << hex << t2.sender() << endl;
secp256k1_start();
Transaction t;
t.nonce = 0;
t.fee = 0;
t.value = 1; // 1 wei.
t.receiveAddress = toAddress(sha3("123"));
bytes sig64 = toBigEndian(t.vrs.r) + toBigEndian(t.vrs.s);
cout << "SIG: " << sig64.size() << " " << asHex(sig64) << " " << t.vrs.v << endl;
@ -48,8 +56,6 @@ int cryptoTest()
bytes privkey = sha3Bytes("123");
secp256k1_start();
{
bytes pubkey(65);
int pubkeylen = 65;
@ -68,6 +74,9 @@ int cryptoTest()
bytes sig(64);
u256 nonce = 0;
int v = 0;
cout << asHex(hmsg) << endl;
cout << asHex(privkey) << endl;
cout << hex << nonce << endl;
int ret = secp256k1_ecdsa_sign_compact((byte const*)hmsg.data(), hmsg.size(), sig.data(), privkey.data(), (byte const*)&nonce, &v);
cout << "MYSIG: " << dec << ret << " " << sig.size() << " " << asHex(sig) << " " << v << endl;

2
test/main.cpp

@ -35,7 +35,7 @@ int main()
rlpTest();
trieTest();
// daggerTest();
// cryptoTest();
cryptoTest();
stateTest();
return 0;
}

31
test/state.cpp

@ -20,43 +20,44 @@
* State test functions.
*/
#include <secp256k1.h>
#include <BlockChain.h>
#include <State.h>
using namespace std;
using namespace eth;
struct KeyPair
{
KeyPair() {}
KeyPair(PrivateKey _k): priv(_k), addr(toPublic(_k)) {}
PrivateKey priv;
Address addr;
};
int stateTest()
{
KeyPair me = sha3("Gav Wood");
KeyPair myMiner = sha3("Gav's Miner");
// KeyPair you = sha3("123");
State s(myMiner.addr);
BlockChain bc("/tmp");
State s(myMiner.address(), "/tmp");
// Mine to get some ether!
s.mine();
s.commitToMine(bc);
while (!s.mine(100)) {}
bc.attemptImport(s.blockData());
s.sync(bc);
bytes tx;
{
Transaction t;
t.nonce = s.transactionsFrom(myMiner.addr);
t.nonce = s.transactionsFrom(myMiner.address());
t.fee = 0;
t.value = 1; // 1 wei.
t.receiveAddress = me.addr;
t.sign(myMiner.priv);
t.value = 1000000000; // 1e9 wei.
t.receiveAddress = me.address();
t.sign(myMiner.secret());
tx = t.rlp();
}
cout << RLP(tx) << endl;
s.execute(tx);
// TODO: Mine to set in stone.
s.commitToMine(bc);
while (!s.mine(100)) {}
bc.attemptImport(s.blockData());
s.sync(bc);
return 0;
}

Loading…
Cancel
Save