From f3d4351dbfc2b4ea9b7d0db7b3c624262e472442 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 24 Mar 2015 08:57:45 +0100 Subject: [PATCH] Make value transfers symmetric. --- libethereum/Executive.cpp | 33 +++++++++++++++++++-------------- libethereum/State.h | 8 ++++++++ libevm/VM.cpp | 6 ------ 3 files changed, 27 insertions(+), 20 deletions(-) diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp index ddfd20956..c23047870 100644 --- a/libethereum/Executive.cpp +++ b/libethereum/Executive.cpp @@ -80,27 +80,31 @@ bool Executive::setup() } // Check gas cost is enough. - auto gasCost = Interface::txGas(m_t.data()); + auto gasRequired = Interface::txGas(m_t.data()); - if (m_t.gas() < gasCost) + if (m_t.gas() < gasRequired) { - clog(StateDetail) << "Not enough gas to pay for the transaction: Require >" << gasCost << " Got" << m_t.gas(); - BOOST_THROW_EXCEPTION(OutOfGas() << RequirementError((bigint)gasCost, (bigint)m_t.gas())); + clog(StateDetail) << "Not enough gas to pay for the transaction: Require >" << gasRequired << " Got" << m_t.gas(); + m_excepted = TransactionException::OutOfGas; + BOOST_THROW_EXCEPTION(OutOfGas() << RequirementError((bigint)gasRequired, (bigint)m_t.gas())); } - bigint cost = m_t.value() + (bigint)m_t.gas() * m_t.gasPrice(); + bigint gasCost = (bigint)m_t.gas() * m_t.gasPrice(); + bigint totalCost = m_t.value() + gasCost; // Avoid unaffordable transactions. - if (m_s.balance(m_t.sender()) < cost) + if (m_s.balance(m_t.sender()) < totalCost) { - clog(StateDetail) << "Not enough cash: Require >" << cost << " Got" << m_s.balance(m_t.sender()); - BOOST_THROW_EXCEPTION(NotEnoughCash() << RequirementError(cost, (bigint)m_s.balance(m_t.sender()))); + clog(StateDetail) << "Not enough cash: Require >" << totalCost << " Got" << m_s.balance(m_t.sender()); + m_excepted = TransactionException::NotEnoughCash; + BOOST_THROW_EXCEPTION(NotEnoughCash() << RequirementError(totalCost, (bigint)m_s.balance(m_t.sender()))); } u256 startGasUsed = m_s.gasUsed(); if (startGasUsed + (bigint)m_t.gas() > m_s.m_currentBlock.gasLimit) { clog(StateDetail) << "Too much gas used in this block: Require <" << (m_s.m_currentBlock.gasLimit - startGasUsed) << " Got" << m_t.gas(); + m_excepted = TransactionException::BlockGasLimitReached; BOOST_THROW_EXCEPTION(BlockGasLimitReached() << RequirementError((bigint)(m_s.m_currentBlock.gasLimit - startGasUsed), (bigint)m_t.gas())); } @@ -108,8 +112,8 @@ bool Executive::setup() m_s.noteSending(m_t.sender()); // Pay... - clog(StateDetail) << "Paying" << formatBalance(u256(cost)) << "from sender (includes" << m_t.gas() << "gas at" << formatBalance(m_t.gasPrice()) << ")"; - m_s.subBalance(m_t.sender(), cost); + clog(StateDetail) << "Paying" << formatBalance(u256(gasCost)) << "from sender for gas (" << m_t.gas() << "gas at" << formatBalance(m_t.gasPrice()) << ")"; + m_s.subBalance(m_t.sender(), gasCost); if (m_t.isCreation()) return create(m_t.sender(), m_t.value(), m_t.gasPrice(), m_t.gas() - (u256)gasCost, &m_t.data(), m_t.sender()); @@ -120,7 +124,6 @@ bool Executive::setup() bool Executive::call(Address _receiveAddress, Address _codeAddress, Address _senderAddress, u256 _value, u256 _gasPrice, bytesConstRef _data, u256 _gas, Address _originAddress) { m_isCreation = false; - m_excepted = TransactionException::None; // cnote << "Transferring" << formatBalance(_value) << "to receiver."; auto it = !(_codeAddress & ~h160(0xffffffff)) ? precompiled().find((unsigned)(u160)_codeAddress) : precompiled().end(); if (it != precompiled().end()) @@ -130,6 +133,8 @@ bool Executive::call(Address _receiveAddress, Address _codeAddress, Address _sen { m_endGas = 0; m_excepted = TransactionException::OutOfGasBase; + // Bail from exception. + return true; // true actually means "all finished - nothing more to be done regarding go(). } else { @@ -147,8 +152,7 @@ bool Executive::call(Address _receiveAddress, Address _codeAddress, Address _sen else m_endGas = _gas; - if (m_excepted == TransactionException::None) - m_s.addBalance(_receiveAddress, _value); + m_s.transferBalance(_senderAddress, _receiveAddress, _value); return !m_ext; } @@ -168,7 +172,8 @@ bool Executive::create(Address _sender, u256 _endowment, u256 _gasPrice, u256 _g m_ext = make_shared(m_s, m_lastHashes, m_newAddress, _sender, _origin, _endowment, _gasPrice, bytesConstRef(), _init, m_depth); } - m_s.m_cache[m_newAddress] = Account(m_s.balance(m_newAddress) + _endowment, Account::ContractConception); + m_s.m_cache[m_newAddress] = Account(m_s.balance(m_newAddress), Account::ContractConception); + m_s.transferBalance(_sender, m_newAddress, _endowment); if (_init.empty()) { diff --git a/libethereum/State.h b/libethereum/State.h index 36d3e7c09..46a111a9b 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -219,6 +219,14 @@ public: */ void subBalance(Address _id, bigint _value); + /** + * @brief Transfers "the balance @a _value between two accounts. + * @param _from Account from which @a _value will be deducted. + * @param _to Account to which @a _value will be added. + * @param _value Amount to be transferred. + */ + void transferBalance(Address _from, Address _to, u256 _value) { subBalance(_from, _value); addBalance(_to, _value); } + /// Get the root of the storage of an account. h256 storageRoot(Address _contract) const; diff --git a/libevm/VM.cpp b/libevm/VM.cpp index 2c1627db9..33c943938 100644 --- a/libevm/VM.cpp +++ b/libevm/VM.cpp @@ -614,10 +614,7 @@ bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _steps) m_stack.pop_back(); if (_ext.balance(_ext.myAddress) >= endowment && _ext.depth < 1024) - { - _ext.subBalance(endowment); m_stack.push_back((u160)_ext.create(endowment, m_gas, bytesConstRef(m_temp.data() + initOff, initSize), _onOp)); - } else m_stack.push_back(0); break; @@ -644,10 +641,7 @@ bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _steps) m_stack.pop_back(); if (_ext.balance(_ext.myAddress) >= value && _ext.depth < 1024) - { - _ext.subBalance(value); m_stack.push_back(_ext.call(inst == Instruction::CALL ? receiveAddress : _ext.myAddress, value, bytesConstRef(m_temp.data() + inOff, inSize), gas, bytesRef(m_temp.data() + outOff, outSize), _onOp, {}, receiveAddress)); - } else m_stack.push_back(0);