Browse Source

Move to canon ES-1.

Minor fix for contracts.
cl-refactor
Gav Wood 11 years ago
parent
commit
c186d8f4d8
  1. 5
      TODO
  2. 6
      alethzero/MainWin.cpp
  3. 35
      libethereum/BlockChain.cpp
  4. 2
      libethereum/BlockChain.h
  5. 2
      libethereum/BlockInfo.cpp
  6. 39
      libethereum/Client.cpp
  7. 14
      libethereum/Client.h
  8. 10
      libethereum/Exceptions.h
  9. 120
      libethereum/Instruction.h
  10. 141
      libethereum/State.cpp
  11. 42
      libethereum/State.h
  12. 26
      test/vm.cpp

5
TODO

@ -18,6 +18,10 @@ Network:
- Solid communications?
- Strategy for peer suggestion?
Cleanups & caching
- All caches should flush unused data (I'm looking at you, BlockChain) to avoid memory overload.
- State DB should keep only last few N blocks worth of nodes (except for restore points - configurable, defaults to every 30000th block - all blocks that are restore points should be stored so their stateRoots are known good).
THREAD-SAFETY
- BlockChain
- TransactionQueue
@ -43,6 +47,7 @@ GUI
- Make address/block chain list model-based, JIT populated.
- Make everything else model-based
- Qt/QML class.
- Turn on/off debug channels.
For PoC3:
- Shared contract acceptence tests.

6
alethzero/MainWin.cpp

@ -65,7 +65,7 @@ Main::~Main()
void Main::on_about_triggered()
{
QMessageBox::about(this, "About AlethZero PoC-2", "AlethZero/v" ADD_QUOTES(ETH_VERSION) "/" ADD_QUOTES(ETH_BUILD_TYPE) "/" ADD_QUOTES(ETH_BUILD_PLATFORM) "\nBy Gav Wood, 2014.\nBased on a design by Vitalik Buterin.\n\nTeam Ethereum++ includes: Eric Lombrozo, Marko Simovic, Alex Leverington and several others.");
QMessageBox::about(this, "About AlethZero PoC-3", "AlethZero/v" ADD_QUOTES(ETH_VERSION) "/" ADD_QUOTES(ETH_BUILD_TYPE) "/" ADD_QUOTES(ETH_BUILD_PLATFORM) "\nBy Gav Wood, 2014.\nBased on a design by Vitalik Buterin.\n\nTeam Ethereum++ includes: Eric Lombrozo, Marko Simovic, Alex Leverington, Tim Hughes and several others.");
}
void Main::writeSettings()
@ -305,11 +305,11 @@ void Main::on_send_clicked()
u256 totalReq = value() + fee();
m_client->lock();
for (auto i: m_myKeys)
if (m_client->state().balance(i.address()) >= totalReq && i.address() != Address(fromUserHex(ui->destination->text().toStdString())))
if (m_client->state().balance(i.address()) >= totalReq/* && i.address() != Address(fromUserHex(ui->destination->text().toStdString()))*/)
{
m_client->unlock();
Secret s = i.secret();
Address r = Address(fromUserHex(ui->destination->text().toStdString()));
Address r = ui->destination->text().size() ? Address(fromUserHex(ui->destination->text().toStdString())) : Address();
m_client->transact(s, r, value(), assemble(ui->data->toPlainText().toStdString()));
refresh();
return;

35
libethereum/BlockChain.cpp

@ -116,20 +116,41 @@ bool contains(T const& _t, V const& _v)
return false;
}
bool BlockChain::attemptImport(bytes const& _block, Overlay const& _stateDB)
{
#if ETH_CATCH
try
#endif
{
import(_block, _stateDB);
return true;
}
#if ETH_CATCH
catch (...)
{
return false;
}
#endif
}
void BlockChain::import(bytes const& _block, Overlay const& _db)
{
// VERIFY: populates from the block and checks the block is internally coherent.
BlockInfo bi(&_block);
#if ETH_CATCH
try
#endif
{
bi.verifyInternals(&_block);
}
#if ETH_CATCH
catch (Exception const& _e)
{
clog(BlockChainNote) << " Malformed block (" << _e.description() << ").";
throw;
}
#endif
auto newHash = eth::sha3(_block);
// Check block doesn't already exist first!
@ -151,7 +172,9 @@ void BlockChain::import(bytes const& _block, Overlay const& _db)
clog(BlockChainNote) << "Attempting import of " << newHash << "...";
u256 td;
#if ETH_CATCH
try
#endif
{
// Check family:
BlockInfo biParent(block(bi.parentHash));
@ -168,7 +191,7 @@ void BlockChain::import(bytes const& _block, Overlay const& _db)
auto tdIncrease = s.playback(&_block, bi, biParent, biGrandParent, true);
td = pd.totalDifficulty + tdIncrease;
#if PARANOIA
#if ETH_PARANOIA
checkConsistency();
#endif
// All ok - insert into DB
@ -182,15 +205,17 @@ void BlockChain::import(bytes const& _block, Overlay const& _db)
m_detailsDB->Put(m_writeOptions, ldb::Slice((char const*)&bi.parentHash, 32), (ldb::Slice)eth::ref(m_details[bi.parentHash].rlp()));
m_db->Put(m_writeOptions, ldb::Slice((char const*)&newHash, 32), (ldb::Slice)ref(_block));
#if PARANOIA
#if ETH_PARANOIA
checkConsistency();
#endif
}
catch (...)
#if ETH_CATCH
catch (Exception const& _e)
{
clog(BlockChainNote) << " Malformed block.";
clog(BlockChainNote) << " Malformed block (" << _e.description() << ").";
throw;
}
#endif
// cnote << "Parent " << bi.parentHash << " has " << details(bi.parentHash).children.size() << " children.";

2
libethereum/BlockChain.h

@ -74,7 +74,7 @@ public:
void process();
/// Attempt to import the given block.
bool attemptImport(bytes const& _block, Overlay const& _stateDB) { try { import(_block, _stateDB); return true; } catch (...) { return false; } }
bool attemptImport(bytes const& _block, Overlay const& _stateDB);
/// Import block into disk-backed DB
void import(bytes const& _block, Overlay const& _stateDB);

2
libethereum/BlockInfo.cpp

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

39
libethereum/Client.cpp

@ -32,17 +32,15 @@ Client::Client(std::string const& _clientVersion, Address _us, std::string const
m_clientVersion(_clientVersion),
m_bc(_dbPath),
m_stateDB(State::openDB(_dbPath)),
m_s(_us, m_stateDB),
m_mined(_us, m_stateDB)
m_preMine(_us, m_stateDB),
m_postMine(_us, m_stateDB)
{
Defaults::setDBPath(_dbPath);
// Synchronise the state according to the block chain - i.e. replay all transactions in block chain, in order.
// In practise this won't need to be done since the State DB will contain the keys for the tries for most recent (and many old) blocks.
// Synchronise the state according to the head of the block chain.
// TODO: currently it contains keys for *all* blocks. Make it remove old ones.
m_s.sync(m_bc);
m_s.sync(m_tq);
m_mined = m_s;
m_preMine.sync(m_bc);
m_postMine = m_preMine;
m_changed = true;
static const char* c_threadName = "eth";
@ -88,7 +86,7 @@ void Client::stopNetwork()
void Client::startMining()
{
m_doMine = true;
m_miningStarted = true;
m_restartMining = true;
}
void Client::stopMining()
@ -100,7 +98,7 @@ void Client::transact(Secret _secret, Address _dest, u256 _amount, u256s _data)
{
lock_guard<mutex> l(m_lock);
Transaction t;
t.nonce = m_mined.transactionsFrom(toAddress(_secret));
t.nonce = m_postMine.transactionsFrom(toAddress(_secret));
t.receiveAddress = _dest;
t.value = _amount;
t.data = _data;
@ -135,35 +133,35 @@ void Client::work()
// Resynchronise state with block chain & trans
{
lock_guard<mutex> l(m_lock);
if (m_s.sync(m_bc))
if (m_preMine.sync(m_bc) || m_postMine.address() != m_preMine.address())
{
if (m_doMine)
cnote << "Externally mined block: Restarting mining operation.";
cnote << "New block on chain: Restarting mining operation.";
changed = true;
m_miningStarted = true; // need to re-commit to mine.
m_mined = m_s;
m_restartMining = true; // need to re-commit to mine.
m_postMine = m_preMine;
}
if (m_mined.sync(m_tq))
if (m_postMine.sync(m_tq))
{
if (m_doMine)
cnote << "Additional transaction ready: Restarting mining operation.";
changed = true;
m_miningStarted = true;
m_restartMining = true;
}
}
if (m_doMine)
{
if (m_miningStarted)
if (m_restartMining)
{
lock_guard<mutex> l(m_lock);
m_mined.commitToMine(m_bc);
m_postMine.commitToMine(m_bc);
}
m_miningStarted = false;
m_restartMining = false;
// Mine for a while.
MineInfo mineInfo = m_mined.mine(100);
MineInfo mineInfo = m_postMine.mine(100);
m_mineProgress.best = max(m_mineProgress.best, mineInfo.best);
m_mineProgress.current = mineInfo.best;
m_mineProgress.requirement = mineInfo.requirement;
@ -172,10 +170,9 @@ void Client::work()
{
// Import block.
lock_guard<mutex> l(m_lock);
m_bc.attemptImport(m_mined.blockData(), m_stateDB);
m_bc.attemptImport(m_postMine.blockData(), m_stateDB);
m_mineProgress.best = 0;
m_changed = true;
m_miningStarted = true; // need to re-commit to mine.
}
}
else

14
libethereum/Client.h

@ -90,11 +90,11 @@ public:
bool changed() const { auto ret = m_changed; m_changed = false; return ret; }
/// Get the object representing the current state of Ethereum.
State const& state() const { return m_s; }
State const& state() const { return m_preMine; }
/// Get the object representing the current canonical blockchain.
BlockChain const& blockChain() const { return m_bc; }
/// Get a map containing each of the pending transactions.
std::map<h256, Transaction> const& pending() const { return m_mined.pending(); }
std::map<h256, Transaction> const& pending() const { return m_postMine.pending(); }
void setClientVersion(std::string const& _name) { m_clientVersion = _name; }
@ -117,9 +117,9 @@ public:
// Mining stuff:
/// Set the coinbase address.
void setAddress(Address _us) { m_s.setAddress(_us); }
void setAddress(Address _us) { m_preMine.setAddress(_us); }
/// Get the coinbase address.
Address address() const { return m_s.address(); }
Address address() const { return m_preMine.address(); }
/// Start mining.
void startMining();
/// Stop mining.
@ -134,8 +134,8 @@ private:
BlockChain m_bc; ///< Maintains block database.
TransactionQueue m_tq; ///< Maintains list of incoming transactions not yet on the block chain.
Overlay m_stateDB; ///< Acts as the central point for the state database, so multiple States can share it.
State m_s; ///< The present state of the client.
State m_mined; ///< The state of the client which we're mining (i.e. it'll have all the rewards added).
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).
PeerServer* m_net = nullptr; ///< Should run in background and send us events when blocks found and allow us to send blocks as required.
std::thread* m_work; ///< The work thread.
@ -144,7 +144,7 @@ private:
enum { Active = 0, Deleting, Deleted } m_workState = Active;
bool m_doMine = false; ///< Are we supposed to be mining?
MineProgress m_mineProgress;
mutable bool m_miningStarted = false;
mutable bool m_restartMining = false;
mutable bool m_changed;
};

10
libethereum/Exceptions.h

@ -15,10 +15,12 @@ public:
class BadHexCharacter: public Exception {};
class NotEnoughCash: public Exception {};
class BadInstruction: public Exception {};
class StackTooSmall: public Exception { public: StackTooSmall(u256 _req, u256 _got): req(_req), got(_got) {} u256 req; u256 got; };
class OperandOutOfRange: public Exception { public: OperandOutOfRange(u256 _min, u256 _max, u256 _got): mn(_min), mx(_max), got(_got) {} u256 mn; u256 mx; u256 got; };
class ExecutionException: public Exception {};
class VMException: public Exception {};
class BadInstruction: public VMException {};
class StackTooSmall: public VMException { public: StackTooSmall(u256 _req, u256 _got): req(_req), got(_got) {} u256 req; u256 got; };
class OperandOutOfRange: public VMException { public: OperandOutOfRange(u256 _min, u256 _max, u256 _got): mn(_min), mx(_max), got(_got) {} u256 mn; u256 mx; u256 got; };
class NoSuchContract: public Exception {};
class ContractAddressCollision: public Exception {};
class FeeTooSmall: public Exception {};

120
libethereum/Instruction.h

@ -47,10 +47,8 @@ enum class Instruction: uint8_t
GE,
EQ,
NOT,
MYADDRESS = 0x10,
TXSENDER, ///< pushes the transaction sender
TXVALUE , ///< pushes the transaction value
TXFEE, ///< pushes the transaction fee
TXDATAN, ///< pushes the number of data items
TXDATA, ///< pops one item and pushes data item S[-1], or zero if index out of range
BLK_PREVHASH, ///< pushes the hash of the previous block (NOT the current one since that's impossible!)
@ -58,6 +56,8 @@ enum class Instruction: uint8_t
BLK_TIMESTAMP, ///< pushes the timestamp of the current block
BLK_NUMBER, ///< pushes the current block number
BLK_DIFFICULTY, ///< pushes the difficulty of the current block
BLK_NONCE,
BASEFEE,
SHA256 = 0x20,
RIPEMD160,
ECMUL,
@ -69,72 +69,72 @@ enum class Instruction: uint8_t
PUSH = 0x30,
POP,
DUP,
DUPN,
SWAP,
SWAPN,
LOAD,
STORE,
JMP = 0x40,
MLOAD,
MSTORE,
SLOAD,
SSTORE,
JMP,
JMPI,
IND,
EXTRO = 0x50,
EXTRO,
BALANCE,
MKTX = 0x60,
SUICIDE = 0xff
MKTX,
SUICIDE = 0x3f
};
static const std::map<std::string, Instruction> c_instructions =
{
{ "STOP", (Instruction)0x00 },
{ "ADD", (Instruction)0x01 },
{ "SUB", (Instruction)0x02 },
{ "MUL", (Instruction)0x03 },
{ "DIV", (Instruction)0x04 },
{ "SDIV", (Instruction)0x05 },
{ "MOD", (Instruction)0x06 },
{ "SMOD", (Instruction)0x07 },
{ "EXP", (Instruction)0x08 },
{ "NEG", (Instruction)0x09 },
{ "LT", (Instruction)0x0a },
{ "LE", (Instruction)0x0b },
{ "GT", (Instruction)0x0c },
{ "GE", (Instruction)0x0d },
{ "EQ", (Instruction)0x0e },
{ "NOT", (Instruction)0x0f },
{ "MYADDRESS", (Instruction)0x10 },
{ "TXSENDER", (Instruction)0x11 },
{ "TXVALUE", (Instruction)0x12 },
{ "TXFEE", (Instruction)0x13 },
{ "TXDATAN", (Instruction)0x14 },
{ "TXDATA", (Instruction)0x15 },
{ "BLK_PREVHASH", (Instruction)0x16 },
{ "BLK_COINBASE", (Instruction)0x17 },
{ "BLK_TIMESTAMP", (Instruction)0x18 },
{ "BLK_NUMBER", (Instruction)0x19 },
{ "BLK_DIFFICULTY", (Instruction)0x1a },
{ "SHA256", (Instruction)0x20 },
{ "RIPEMD160", (Instruction)0x21 },
{ "ECMUL", (Instruction)0x22 },
{ "ECADD", (Instruction)0x23 },
{ "ECSIGN", (Instruction)0x24 },
{ "ECRECOVER", (Instruction)0x25 },
{ "ECVALID", (Instruction)0x26 },
{ "SHA3", (Instruction)0x27 },
{ "PUSH", (Instruction)0x30 },
{ "POP", (Instruction)0x31 },
{ "DUP", (Instruction)0x32 },
{ "DUPN", (Instruction)0x33 },
{ "SWAP", (Instruction)0x34 },
{ "SWAPN", (Instruction)0x35 },
{ "LOAD", (Instruction)0x36 },
{ "STORE", (Instruction)0x37 },
{ "JMP", (Instruction)0x40 },
{ "JMPI", (Instruction)0x41 },
{ "IND", (Instruction)0x42 },
{ "EXTRO", (Instruction)0x50 },
{ "BALANCE", (Instruction)0x51 },
{ "MKTX", (Instruction)0x60 },
{ "SUICIDE", (Instruction)0xff }
{ "STOP", Instruction::STOP },
{ "ADD", Instruction::ADD },
{ "SUB", Instruction::SUB },
{ "MUL", Instruction::MUL },
{ "DIV", Instruction::DIV },
{ "SDIV", Instruction::SDIV },
{ "MOD", Instruction::MOD },
{ "SMOD", Instruction::SMOD },
{ "EXP", Instruction::EXP },
{ "NEG", Instruction::NEG },
{ "LT", Instruction::LT },
{ "LE", Instruction::LE },
{ "GT", Instruction::GT },
{ "GE", Instruction::GE },
{ "EQ", Instruction::EQ },
{ "NOT", Instruction::NOT },
{ "TXSENDER", Instruction::TXSENDER },
{ "TXVALUE", Instruction::TXVALUE },
{ "TXDATAN", Instruction::TXDATAN },
{ "TXDATA", Instruction::TXDATA },
{ "BLK_PREVHASH", Instruction::BLK_PREVHASH },
{ "BLK_COINBASE", Instruction::BLK_COINBASE },
{ "BLK_TIMESTAMP", Instruction::BLK_TIMESTAMP },
{ "BLK_NUMBER", Instruction::BLK_NUMBER },
{ "BLK_DIFFICULTY", Instruction::BLK_DIFFICULTY },
{ "BLK_NONCE", Instruction::BLK_NONCE },
{ "BASFEEE", Instruction::BASEFEE },
{ "SHA256", Instruction::SHA256 },
{ "RIPEMD160", Instruction::RIPEMD160 },
{ "ECMUL", Instruction::ECMUL },
{ "ECADD", Instruction::ECADD },
{ "ECSIGN", Instruction::ECSIGN },
{ "ECRECOVER", Instruction::ECRECOVER },
{ "ECVALID", Instruction::ECVALID },
{ "SHA3", Instruction::SHA3 },
{ "PUSH", Instruction::PUSH },
{ "POP", Instruction::POP },
{ "DUP", Instruction::DUP },
{ "SWAP", Instruction::SWAP },
{ "MLOAD", Instruction::MLOAD },
{ "MSTORE", Instruction::MSTORE },
{ "SLOAD", Instruction::SLOAD },
{ "SSTORE", Instruction::SSTORE },
{ "JMP", Instruction::JMP },
{ "JMPI", Instruction::JMPI },
{ "IND", Instruction::IND },
{ "EXTRO", Instruction::EXTRO },
{ "BALANCE", Instruction::BALANCE },
{ "MKTX", Instruction::MKTX },
{ "SUICIDE", Instruction::SUICIDE }
};
u256s assemble(std::string const& _code);

141
libethereum/State.cpp

@ -48,13 +48,13 @@ using namespace eth;
u256 const c_stepFee = 1;
u256 const c_dataFee = 20;
u256 const c_memoryFee = 5;
u256 const c_memoryFee = 0;//5; memoryFee is 0 for PoC-3
u256 const c_extroFee = 40;
u256 const c_cryptoFee = 20;
u256 const c_newContractFee = 100;
u256 const c_txFee = 100;
u256 const eth::c_genesisDifficulty = (u256)1 << 22;
u256 eth::c_genesisDifficulty = (u256)1 << 22;
std::map<Address, AddressState> const& eth::genesisState()
{
@ -63,7 +63,7 @@ std::map<Address, AddressState> const& eth::genesisState()
{
// Initialise.
s_ret[Address(fromUserHex("8a40bfaa73256b60764c1bf40675a99083efb075"))] = AddressState(u256(1) << 200, 0, AddressType::Normal);
s_ret[Address(fromUserHex("93658b04240e4bd4046fd2d6d417d20f146f4b43"))] = AddressState(u256(1) << 200, 0, AddressType::Normal);
s_ret[Address(fromUserHex("e6716f9544a56c530d868e4bfbacb172315bdead"))] = AddressState(u256(1) << 200, 0, AddressType::Normal);
s_ret[Address(fromUserHex("1e12515ce3e0f817a4ddef9ca55788a1d66bd2df"))] = AddressState(u256(1) << 200, 0, AddressType::Normal);
s_ret[Address(fromUserHex("1a26338f0d905e295fccb71fa9ea849ffa12aaf4"))] = AddressState(u256(1) << 200, 0, AddressType::Normal);
}
@ -90,8 +90,8 @@ State::State(Address _coinbaseAddress, Overlay const& _db):
m_state(&m_db),
m_ourAddress(_coinbaseAddress)
{
m_blockReward = u256(15000000000) * 100000000;
m_fees.setMultiplier(u256(100000) * 1000000000);
m_blockReward = 1500 * finney;
m_fees.setMultiplier(100 * szabo);
secp256k1_start();
@ -147,6 +147,11 @@ void FeeStructure::setMultiplier(u256 _x)
m_txFee = c_txFee * _x;
}
u256 FeeStructure::multiplier() const
{
return m_stepFee / c_stepFee;
}
void State::ensureCached(Address _a, bool _requireMemory, bool _forceCreate) const
{
auto it = m_cache.find(_a);
@ -171,7 +176,7 @@ void State::ensureCached(Address _a, bool _requireMemory, bool _forceCreate) con
{
// Populate memory.
assert(it->second.type() == AddressType::Contract);
TrieDB<u256, Overlay> memdb(const_cast<Overlay*>(&m_db), it->second.oldRoot()); // promise we won't alter the overlay! :)
TrieDB<h256, Overlay> memdb(const_cast<Overlay*>(&m_db), it->second.oldRoot()); // promise we won't alter the overlay! :)
map<u256, u256>& mem = it->second.setHaveMemory();
for (auto const& i: memdb)
if (mem.find(i.first) == mem.end())
@ -271,6 +276,8 @@ void State::resetCurrent()
m_currentBlock.coinbaseAddress = m_ourAddress;
m_currentBlock.stateRoot = m_previousBlock.stateRoot;
m_currentBlock.parentHash = m_previousBlock.hash;
m_currentBlock.sha3Transactions = h256();
m_currentBlock.sha3Uncles = h256();
m_state.setRoot(m_currentBlock.stateRoot);
}
@ -356,6 +363,9 @@ u256 State::playback(bytesConstRef _block, BlockInfo const& _grandParent, bool _
if (m_currentBlock.parentHash != m_previousBlock.hash)
throw InvalidParentHash();
// cnote << "playback begins:" << m_state.root();
// cnote << m_state;
// All ok with the block generally. Play back the transactions now...
for (auto const& i: RLP(_block)[1])
execute(i.data());
@ -385,9 +395,10 @@ u256 State::playback(bytesConstRef _block, BlockInfo const& _grandParent, bool _
{
cwarn << "Bad state root!";
cnote << "Given to be:" << m_currentBlock.stateRoot;
cnote << TrieDB<Address, Overlay>(&m_db, m_currentBlock.stateRoot);
cnote << "Calculated to be:" << rootHash();
cnote << m_state;
cnote << TrieDB<Address, Overlay>(&m_db, m_currentBlock.stateRoot);
cnote << *this;
// Rollback the trie.
m_db.rollback();
throw InvalidStateRoot();
@ -414,14 +425,15 @@ u256 State::playback(bytesConstRef _block, BlockInfo const& _grandParent, bool _
// (i.e. all the transactions we executed).
void State::commitToMine(BlockChain const& _bc)
{
if (m_previousBlock.hash != m_committedPreviousHash)
if (m_currentBlock.sha3Transactions != h256() || m_currentBlock.sha3Uncles != h256())
{
m_committedPreviousHash = m_previousBlock.hash;
cnote << "Commiting to mine on" << m_previousBlock.hash;
Addresses uncleAddresses;
for (auto i: RLP(m_currentUncles))
uncleAddresses.push_back(i[2].toHash<Address>());
unapplyRewards(uncleAddresses);
}
if (m_currentBlock.sha3Transactions != h256() || m_currentBlock.sha3Uncles != h256())
return;
cnote << "Commiting to mine on" << m_previousBlock.hash;
RLPStream uncles;
Addresses uncleAddresses;
@ -459,6 +471,10 @@ 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();
cnote << "stateRoot:" << m_state.root();
// cnote << m_state;
// cnote << *this;
m_currentBlock.stateRoot = m_state.root();
m_currentBlock.parentHash = m_previousBlock.hash;
}
@ -577,7 +593,7 @@ u256 State::contractMemory(Address _id, u256 _memory) const
return mit->second;
}
// Memory not cached - just grab one item from the DB rather than cache the lot.
TrieDB<u256, Overlay> memdb(const_cast<Overlay*>(&m_db), it->second.oldRoot()); // promise we won't change the overlay! :)
TrieDB<h256, Overlay> memdb(const_cast<Overlay*>(&m_db), it->second.oldRoot()); // promise we won't change the overlay! :)
return RLP(memdb.at(_memory)).toInt<u256>(); // TODO: CHECK: check if this is actually an RLP decode
}
@ -605,6 +621,17 @@ void State::applyRewards(Addresses const& _uncleAddresses)
addBalance(m_currentBlock.coinbaseAddress, r);
}
void State::unapplyRewards(Addresses const& _uncleAddresses)
{
u256 r = m_blockReward;
for (auto const& i: _uncleAddresses)
{
subBalance(i, m_blockReward * 3 / 4);
r += m_blockReward / 8;
}
subBalance(m_currentBlock.coinbaseAddress, r);
}
void State::executeBare(Transaction const& _t, Address _sender)
{
// Entry point for a contract-originated transaction.
@ -634,8 +661,16 @@ void State::executeBare(Transaction const& _t, Address _sender)
if (isContractAddress(_t.receiveAddress))
{
MinerFeeAdder feeAdder({this, 0}); // will add fee on destruction.
execute(_t.receiveAddress, _sender, _t.value, _t.data, &feeAdder.fee);
try
{
MinerFeeAdder feeAdder({this, 0}); // will add fee on destruction.
execute(_t.receiveAddress, _sender, _t.value, _t.data, &feeAdder.fee);
}
catch (VMException const& _e)
{
cnote << "VM Exception: " << _e.description();
throw;
}
}
}
else
@ -690,27 +725,29 @@ void State::execute(Address _myAddress, Address _txSender, u256 _txValue, u256s
throw StackTooSmall(_n, stack.size());
};
ensureCached(_myAddress, true, true);
auto& myMemory = m_cache[_myAddress].memory();
auto& myStore = m_cache[_myAddress].memory();
auto mem = [&](u256 _n) -> u256
auto store = [&](u256 _n) -> u256
{
auto i = myMemory.find(_n);
return i == myMemory.end() ? 0 : i->second;
auto i = myStore.find(_n);
return i == myStore.end() ? 0 : i->second;
};
auto setMem = [&](u256 _n, u256 _v)
auto setStore = [&](u256 _n, u256 _v)
{
if (_v)
{
auto it = myMemory.find(_n);
if (it == myMemory.end())
myMemory.insert(make_pair(_n, _v));
auto it = myStore.find(_n);
if (it == myStore.end())
myStore.insert(make_pair(_n, _v));
else
myMemory.at(_n) = _v;
myStore.at(_n) = _v;
}
else
myMemory.erase(_n);
myStore.erase(_n);
};
map<u256, u256> tempMem;
u256 curPC = 0;
u256 nextPC = 1;
u256 stepCount = 0;
@ -721,21 +758,21 @@ void State::execute(Address _myAddress, Address _txSender, u256 _txValue, u256s
bigint minerFee = stepCount > 16 ? m_fees.m_stepFee : 0;
bigint voidFee = 0;
auto rawInst = mem(curPC);
auto rawInst = store(curPC);
if (rawInst > 0xff)
throw BadInstruction();
Instruction inst = (Instruction)(uint8_t)rawInst;
switch (inst)
{
case Instruction::STORE:
case Instruction::SSTORE:
require(2);
if (!mem(stack.back()) && stack[stack.size() - 2])
if (!store(stack.back()) && stack[stack.size() - 2])
voidFee += m_fees.m_memoryFee;
if (mem(stack.back()) && !stack[stack.size() - 2])
if (store(stack.back()) && !stack[stack.size() - 2])
voidFee -= m_fees.m_memoryFee;
// continue on to...
case Instruction::LOAD:
case Instruction::SLOAD:
minerFee += m_fees.m_dataFee;
break;
@ -851,9 +888,9 @@ void State::execute(Address _myAddress, Address _txSender, u256 _txValue, u256s
stack.back() = stack.back() ? 0 : 1;
stack.pop_back();
break;
case Instruction::MYADDRESS:
/*case Instruction::MYADDRESS:
stack.push_back((u160)_myAddress);
break;
break;*/
case Instruction::TXSENDER:
stack.push_back((u160)_txSender);
break;
@ -882,6 +919,12 @@ void State::execute(Address _myAddress, Address _txSender, u256 _txValue, u256s
case Instruction::BLK_DIFFICULTY:
stack.push_back(m_currentBlock.difficulty);
break;
case Instruction::BLK_NONCE:
stack.push_back(m_currentBlock.nonce);
break;
case Instruction::BASEFEE:
stack.push_back(m_fees.multiplier());
break;
case Instruction::SHA256:
{
uint s = (uint)min(stack.back(), (u256)(stack.size() - 1) * 32);
@ -1057,7 +1100,7 @@ void State::execute(Address _myAddress, Address _txSender, u256 _txValue, u256s
}
case Instruction::PUSH:
{
stack.push_back(mem(curPC + 1));
stack.push_back(store(curPC + 1));
nextPC = curPC + 2;
break;
}
@ -1069,15 +1112,15 @@ void State::execute(Address _myAddress, Address _txSender, u256 _txValue, u256s
require(1);
stack.push_back(stack.back());
break;
case Instruction::DUPN:
/*case Instruction::DUPN:
{
auto s = mem(curPC + 1);
auto s = store(curPC + 1);
if (s == 0 || s > stack.size())
throw OperandOutOfRange(1, stack.size(), s);
stack.push_back(stack[stack.size() - (uint)s]);
nextPC = curPC + 2;
break;
}
}*/
case Instruction::SWAP:
{
require(2);
@ -1086,25 +1129,35 @@ void State::execute(Address _myAddress, Address _txSender, u256 _txValue, u256s
stack[stack.size() - 2] = d;
break;
}
case Instruction::SWAPN:
/*case Instruction::SWAPN:
{
require(1);
auto d = stack.back();
auto s = mem(curPC + 1);
auto s = store(curPC + 1);
if (s == 0 || s > stack.size())
throw OperandOutOfRange(1, stack.size(), s);
stack.back() = stack[stack.size() - (uint)s];
stack[stack.size() - (uint)s] = d;
nextPC = curPC + 2;
break;
}
case Instruction::LOAD:
}*/
case Instruction::MLOAD:
require(1);
stack.back() = tempMem[stack.back()];
break;
case Instruction::MSTORE:
require(2);
tempMem[stack.back()] = stack[stack.size() - 2];
stack.pop_back();
stack.pop_back();
break;
case Instruction::SLOAD:
require(1);
stack.back() = mem(stack.back());
stack.back() = store(stack.back());
break;
case Instruction::STORE:
case Instruction::SSTORE:
require(2);
setMem(stack.back(), stack[stack.size() - 2]);
setStore(stack.back(), stack[stack.size() - 2]);
stack.pop_back();
stack.pop_back();
break;
@ -1168,7 +1221,7 @@ void State::execute(Address _myAddress, Address _txSender, u256 _txValue, u256s
{
require(1);
Address dest = asAddress(stack.back());
u256 minusVoidFee = myMemory.size() * m_fees.m_memoryFee;
u256 minusVoidFee = myStore.size() * m_fees.m_memoryFee;
addBalance(dest, balance(_myAddress) + minusVoidFee);
m_cache[_myAddress].kill();
// ...follow through to...

42
libethereum/State.h

@ -39,7 +39,7 @@ namespace eth
class BlockChain;
extern const u256 c_genesisDifficulty;
extern u256 c_genesisDifficulty;
std::map<Address, AddressState> const& genesisState();
#define ETH_SENDER_PAYS_SETUP 1
@ -48,6 +48,7 @@ struct FeeStructure
{
/// The fee structure. Values yet to be agreed on...
void setMultiplier(u256 _x); ///< The current block multiplier.
u256 multiplier() const;
u256 m_stepFee;
u256 m_dataFee;
u256 m_memoryFee;
@ -166,9 +167,6 @@ public:
/// Get the list of pending transactions.
std::map<h256, Transaction> const& pending() const { return m_transactions; }
/// Finalise the block, applying the earned rewards.
void applyRewards(Addresses const& _uncleAddresses);
/// Execute all transactions within a given block.
/// @returns the additional total difficulty.
/// If the _grandParent is passed, it will check the validity of each of the uncles.
@ -217,6 +215,12 @@ private:
/// Sets m_currentBlock to a clean state, (i.e. no change from m_previousBlock).
void resetCurrent();
/// Finalise the block, applying the earned rewards.
void applyRewards(Addresses const& _uncleAddresses);
/// Unfinalise the block, unapplying the earned rewards.
void unapplyRewards(Addresses const& _uncleAddresses);
Overlay m_db; ///< Our overlay for the state tree.
TrieDB<Address, Overlay> m_state; ///< Our state tree, as an Overlay DB.
std::map<h256, Transaction> m_transactions; ///< The current list of transactions that we've included in the state.
@ -227,7 +231,6 @@ private:
BlockInfo m_currentBlock; ///< The current block's information.
bytes m_currentBytes; ///< The current block.
uint m_currentNumber;
h256 m_committedPreviousHash; ///< Hash of previous block that we are committing to mine.
bytes m_currentTxs;
bytes m_currentUncles;
@ -256,7 +259,17 @@ inline std::ostream& operator<<(std::ostream& _out, State const& _s)
RLP r(i.second);
_out << "[ " << (r.itemCount() == 3 ? "CONTRACT] " : " NORMAL] ") << i.first << ": " << std::dec << r[1].toInt<u256>() << "@" << r[0].toInt<u256>();
if (r.itemCount() == 3)
_out << " &" << r[2].toHash<h256>();
{
_out << " *" << r[2].toHash<h256>();
TrieDB<h256, Overlay> memdb(const_cast<Overlay*>(&_s.m_db), r[2].toHash<h256>()); // promise we won't alter the overlay! :)
std::map<u256, u256> mem;
for (auto const& j: memdb)
{
_out << std::endl << " [" << j.first << ":" << asHex(j.second) << "]";
mem[j.first] = RLP(j.second).toInt<u256>();
}
_out << std::endl << mem;
}
_out << std::endl;
}
else
@ -272,11 +285,20 @@ inline std::ostream& operator<<(std::ostream& _out, State const& _s)
{
if (i.second.haveMemory())
{
_out << std::endl;
_out << i.second.memory();
_out << std::endl << i.second.memory();
}
else
_out << " &" << i.second.oldRoot();
{
_out << " *" << i.second.oldRoot();
TrieDB<h256, Overlay> memdb(const_cast<Overlay*>(&_s.m_db), i.second.oldRoot()); // promise we won't alter the overlay! :)
std::map<u256, u256> mem;
for (auto const& j: memdb)
{
_out << std::endl << " [" << j.first << ":" << asHex(j.second) << "]";
mem[j.first] = RLP(j.second).toInt<u256>();
}
_out << std::endl << mem;
}
}
_out << std::endl;
}
@ -297,7 +319,7 @@ void commit(std::map<Address, AddressState> const& _cache, DB& _db, TrieDB<Addre
{
if (i.second.haveMemory())
{
TrieDB<u256, DB> memdb(&_db);
TrieDB<h256, DB> memdb(&_db);
memdb.init();
for (auto const& j: i.second.memory())
if (j.second)

26
test/vm.cpp

@ -36,13 +36,19 @@ template <> class UnitTest<1>
public:
int operator()()
{
c_genesisDifficulty = (u256)1;
KeyPair p = KeyPair::create();
Overlay o;
Overlay o(State::openDB("/tmp/vmTest", true));
State s(p.address(), o);
BlockChain bc("/tmp/vmTest", true);
cout << s;
s.addBalance(p.address(), Uether);
s.commitToMine(bc);
s.mine(1000000);
bc.attemptImport(s.blockData(), o);
s.sync(bc);
cout << s;
@ -50,7 +56,7 @@ public:
c.receiveAddress = Address();
c.nonce = 0;
c.data = assemble("txsender load txvalue add txsender store stop");
c.data = assemble("txsender sload txvalue add txsender sstore stop");
c.value = ether;
c.sign(p.secret());
s.execute(c.rlp());
@ -58,11 +64,14 @@ public:
cout << s;
s.commit();
s.commitToMine(bc);
s.mine(1000000);
bc.attemptImport(s.blockData(), o);
s.sync(bc);
cout << s;
cout << s.m_db;
// cout << s.m_db;
c.receiveAddress = ca;
c.nonce = 1;
@ -73,6 +82,13 @@ public:
cout << s;
s.commitToMine(bc);
s.mine();
bc.attemptImport(s.blockData(), o);
s.sync(bc);
cout << s;
return 0;
}
};

Loading…
Cancel
Save