diff --git a/eth/main.cpp b/eth/main.cpp index 95026956d..0af33fb81 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -31,9 +31,9 @@ int main() // Our address. Address us; // TODO: should be loaded from config file/set at command-line. - BlockChain bc; // TODO: Implement - should maintain block database. - TransactionQueue tq; // TODO: Implement. - State s(us); // TODO: Switch to disk-backed state (leveldb) + BlockChain bc; // Maintains block database. + TransactionQueue tq; // Maintains list of incoming transactions not yet on the block chain. + State s(us); // TODO: Switch to disk-backed state (leveldb? could do with a diffing DB) // s.restore(); // TODO: Implement - key optimisation. // 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. diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 34ba1d0bb..3593d3f26 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -38,7 +38,8 @@ BlockChain::BlockChain() m_lastBlockHash = m_genesisHash = BlockInfo::genesis().hash; m_genesisBlock = BlockInfo::createGenesisBlock(); - // TODO: Insert details of genesis block. + // Insert details of genesis block. + m_details[m_genesisHash] = { 0, (u256)1 << 36, h256(), {} }; } BlockChain::~BlockChain() @@ -57,8 +58,7 @@ h256s BlockChain::blockChain(h256Set const& _earlyExit) const ret.push_back(i); return ret; } -// _bc.details(m_previousBlock.parentHash).children -// _bc->coinbaseAddress(i) + void BlockChain::import(bytes const& _block) { try diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index 59b13294f..f00c68fd2 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -36,7 +36,7 @@ struct BlockDetails h256s children; }; -static const BlockDetails NullBlockDetails({0, 0, h256()}); +static const BlockDetails NullBlockDetails({ 0, 0, h256(), {} }); static const h256s NullH256s; /** diff --git a/libethereum/BlockInfo.cpp b/libethereum/BlockInfo.cpp index 9c169cc77..7b451cbe7 100644 --- a/libethereum/BlockInfo.cpp +++ b/libethereum/BlockInfo.cpp @@ -50,7 +50,14 @@ bytes BlockInfo::createGenesisBlock() h256 BlockInfo::headerHashWithoutNonce() const { - return sha3((RLPStream(7) << toBigEndianString(parentHash) << toBigEndianString(sha3Uncles) << coinbaseAddress << toBigEndianString(stateRoot) << toBigEndianString(sha3Transactions) << difficulty << timestamp).out()); + return sha3((RLPStream(7) << parentHash << sha3Uncles << coinbaseAddress << stateRoot << sha3Transactions << difficulty << timestamp).out()); +} + +void BlockInfo::fillStream(RLPStream& _s, bool _nonce) const +{ + _s.appendList(_nonce ? 8 : 7) << parentHash << sha3Uncles << coinbaseAddress << stateRoot << sha3Transactions << difficulty << timestamp; + if (_nonce) + _s << nonce; } void BlockInfo::populateGenesis() diff --git a/libethereum/BlockInfo.h b/libethereum/BlockInfo.h index 2ec47e5e7..1fbd8e2fe 100644 --- a/libethereum/BlockInfo.h +++ b/libethereum/BlockInfo.h @@ -46,6 +46,7 @@ public: explicit operator bool() const { return timestamp != Invalid256; } bool operator==(BlockInfo const& _cmp) const { return hash == _cmp.hash && parentHash == _cmp.parentHash && nonce == _cmp.nonce; } + bool operator!=(BlockInfo const& _cmp) const { return !operator==(_cmp); } static BlockInfo const& genesis() { if (!s_genesis) (s_genesis = new BlockInfo)->populateGenesis(); return *s_genesis; } void populate(bytesConstRef _block); @@ -56,6 +57,7 @@ public: /// No-nonce sha3 of the header only. h256 headerHashWithoutNonce() const; + void fillStream(RLPStream& _s, bool _nonce) const; static bytes createGenesisBlock(); diff --git a/libethereum/RLP.h b/libethereum/RLP.h index 268e8c1b1..39da78a5a 100644 --- a/libethereum/RLP.h +++ b/libethereum/RLP.h @@ -315,6 +315,8 @@ public: /// Read the byte stream. bytes const& out() const { return m_out; } + void swapOut(bytes& _dest) { swap(m_out, _dest); } + private: /// Push the node-type byte (using @a _base) along with the item count @a _count. /// @arg _count is number of characters for strings, data-bytes for ints, or items for lists. diff --git a/libethereum/State.cpp b/libethereum/State.cpp index ff0e4cbe9..cbdde75a5 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -45,6 +45,7 @@ State::State(Address _coinbaseAddress): m_ourAddress(_coinbaseAddress) { secp256k1_start(); m_previousBlock = BlockInfo::genesis(); + m_currentBlock.coinbaseAddress = m_ourAddress; } void State::sync(BlockChain const& _bc) @@ -77,6 +78,7 @@ void State::sync(BlockChain const& _bc, h256 _block) m_current.clear(); m_transactions.clear(); m_currentBlock = BlockInfo(); + m_currentBlock.coinbaseAddress = m_ourAddress; ++m_currentNumber; } else if (bi == m_previousBlock) @@ -109,6 +111,7 @@ void State::sync(BlockChain const& _bc, h256 _block) m_current.clear(); m_currentBlock = BlockInfo(); m_currentNumber = _bc.details(_bc.currentHash()).number + 1; + m_currentBlock.coinbaseAddress = m_ourAddress; } } @@ -198,6 +201,40 @@ u256 State::playback(bytesConstRef _block, BlockInfo const& _grandParent) return tdIncrease; } +// @returns the block that represents the difference between m_previousBlock and m_currentBlock. +// (i.e. all the transactions we executed). +bytes State::compileBlock(BlockChain const& _bc) +{ + RLPStream uncles; + 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); + } + else + uncles.appendList(0); + + RLPStream txs(m_transactions.size()); + for (auto const& i: m_transactions) + i.second.fillStream(txs); + + txs.swapOut(m_currentTxs); + uncles.swapOut(m_currentUncles); + + m_currentBlock.sha3Transactions = sha3(m_currentTxs); + m_currentBlock.sha3Uncles = sha3(m_currentUncles); + + RLPStream ret; + ret.appendList(3); + m_currentBlock.fillStream(ret, true); + ret.appendRaw(m_currentTxs); + ret.appendRaw(m_currentUncles); + return ret.out(); +} + h256 State::rootHash() const { // TODO! diff --git a/libethereum/State.h b/libethereum/State.h index e84fa23d7..98d3ae539 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -114,6 +114,8 @@ public: /// This might throw. u256 playback(bytesConstRef _block, BlockInfo const& _bi, BlockInfo const& _parent, BlockInfo const& _grandParent); + bytes compileBlock(BlockChain const& _bc); + private: /// Fee-adder on destruction RAII class. struct MinerFeeAdder @@ -147,6 +149,9 @@ private: bytes m_currentBytes; ///< The current block. uint m_currentNumber; + bytes m_currentTxs; + bytes m_currentUncles; + Address m_ourAddress; ///< Our address (i.e. the address to which fees go). /// The fee structure. Values yet to be agreed on... diff --git a/libethereum/Trie.cpp b/libethereum/Trie.cpp index d64ca3d30..12ed53831 100644 --- a/libethereum/Trie.cpp +++ b/libethereum/Trie.cpp @@ -200,6 +200,19 @@ h256 hash256(StringMap const& _s) return sha3(s.out()); } +bytes rlp256(StringMap const& _s) +{ + // build patricia tree. + if (_s.empty()) + return RLPNull; + HexMap hexMap; + for (auto i = _s.rbegin(); i != _s.rend(); ++i) + hexMap[toHex(i->first)] = i->second; + RLPStream s; + hash256aux(hexMap, hexMap.cbegin(), hexMap.cend(), 0, s); + return s.out(); +} + h256 hash256(u256Map const& _s) { // build patricia tree. diff --git a/libethereum/Trie.h b/libethereum/Trie.h index 1a6bdc73b..c80b30790 100644 --- a/libethereum/Trie.h +++ b/libethereum/Trie.h @@ -27,6 +27,7 @@ namespace eth { +bytes rlp256(StringMap const& _s); h256 hash256(StringMap const& _s); h256 hash256(u256Map const& _s); std::string hexPrefixEncode(bytes const& _hexVector, bool _terminated = false, int _begin = 0, int _end = -1); diff --git a/test/main.cpp b/test/main.cpp index 3587a1ee6..35f3fc20d 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -36,6 +36,7 @@ using namespace eth; int main() { +/* // Test dagger { Dagger d((h256)0); @@ -53,6 +54,7 @@ int main() cout << hex << d.eval(1); cout << " " << dec << duration_cast(steady_clock::now() - s).count() << " ms" << endl; } + */ /* // Test transaction. bytes tx = fromUserHex("88005401010101010101010101010101010101010101011f0de0b6b3a76400001ce8d4a5100080181c373130a009ba1f10285d4e659568bfcfec85067855c5a3c150100815dad4ef98fd37cf0593828c89db94bd6c64e210a32ef8956eaa81ea9307194996a3b879441f5d"); @@ -111,6 +113,9 @@ int main() cout << "SENDER: " << hex << low160(eth::sha3(bytesConstRef(&pubkey).cropped(1))) << endl; } */ + cout << escaped(asString(rlp256({{"b", "B"}, {"a", "A"}})), false) << " == " << RLP(rlp256({{"b", "B"}, {"a", "A"}})) << endl; + cout << escaped(asString(rlp256({{"test", "test"}})), false) << " == " << RLP(rlp256({{"test", "test"}})) << endl; + cout << asHex(rlp256({{"test", "test"}, {"te", "test"}})) << endl; { Trie t; t.insert("dog", "puppy");