<commit_before>/*
	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.

	cpp-ethereum 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 cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/** @file Executive.cpp
 * @author <NAME> <<EMAIL>>
 * @date 2014
 */

#include <boost/timer.hpp>
#include <libdevcore/CommonIO.h>
#include <libevm/VM.h>
#include "Executive.h"
#include "State.h"
#include "ExtVM.h"
using namespace std;
using namespace dev;
using namespace dev::eth;

#define ETH_VMTRACE 1

Executive::~Executive()
{
	// TODO: Make safe.
	delete m_ext;
	delete m_vm;
}

u256 Executive::gasUsed() const
{
	return m_t.gas() - m_endGas;
}

bool Executive::setup(bytesConstRef _rlp)
{
	// Entry point for a user-executed transaction.
	m_t = Transaction(_rlp);

	m_sender = m_t.sender();

	// Avoid invalid transactions.
	auto nonceReq = m_s.transactionsFrom(m_sender);
	if (m_t.nonce() != nonceReq)
	{
		clog(StateDetail) << "Invalid Nonce: Require" << nonceReq << " Got" << m_t.nonce();
		BOOST_THROW_EXCEPTION(InvalidNonce(nonceReq, m_t.nonce()));
	}

	// Don't like transactions whose gas price is too low. NOTE: this won't stay here forever - it's just until we get a proper gas price discovery protocol going.
	if (m_t.gasPrice() < m_s.m_currentBlock.minGasPrice)
	{
		clog(StateDetail) << "Offered gas-price is too low: Require >" << m_s.m_currentBlock.minGasPrice << " Got" << m_t.gasPrice();
		BOOST_THROW_EXCEPTION(GasPriceTooLow());
	}

	// Check gas cost is enough.
	u256 gasCost = m_t.data().size() * c_txDataGas + c_txGas;

	if (m_t.gas() < gasCost)
	{
		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()));
	}

	u256 cost = m_t.value() + m_t.gas() * m_t.gasPrice();

	// Avoid unaffordable transactions.
	if (m_s.balance(m_sender) < cost)
	{
		clog(StateDetail) << "Not enough cash: Require >" << cost << " Got" << m_s.balance(m_sender);
		BOOST_THROW_EXCEPTION(NotEnoughCash() << RequirementError((bigint)cost, (bigint)m_s.balance(m_sender)));
	}

	u256 startGasUsed = m_s.gasUsed();
	if (startGasUsed + 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();
		BOOST_THROW_EXCEPTION(BlockGasLimitReached() << RequirementError((bigint)(m_s.m_currentBlock.gasLimit - startGasUsed), (bigint)m_t.gas()));
	}

	// Increment associated nonce for sender.
	m_s.noteSending(m_sender);

	// Pay...
	clog(StateDetail) << "Paying" << formatBalance(cost) << "from sender (includes" << m_t.gas() << "gas at" << formatBalance(m_t.gasPrice()) << ")";
	m_s.subBalance(m_sender, cost);

	if (m_ms)
	{
		m_ms->from = m_sender;
		m_ms->to = m_t.receiveAddress();
		m_ms->value = m_t.value();
		m_ms->input = m_t.data();
	}

	if (m_t.isCreation())
		return create(m_sender, m_t.value(), m_t.gasPrice(), m_t.gas() - gasCost, &m_t.data(), m_sender);
	else
		return call(m_t.receiveAddress(), m_sender, m_t.value(), m_t.gasPrice(), bytesConstRef(&m_t.data()), m_t.gas() - gasCost, m_sender);
}

bool Executive::call(Address _receiveAddress, Address _senderAddress, u256 _value, u256 _gasPrice, bytesConstRef _data, u256 _gas, Address _originAddress)
{
//	cnote << "Transferring" << formatBalance(_value) << "to receiver.";
	m_s.addBalance(_receiveAddress, _value);

	if (m_s.addressHasCode(_receiveAddress))
	{
		m_vm = VMFace::create(VMFace::Interpreter, _gas).release();
		bytes const& c = m_s.code(_receiveAddress);
		m_ext = new ExtVM(m_s, _receiveAddress, _senderAddress, _originAddress, _value, _gasPrice, _data, &c, m_ms);
	}
	else
		m_endGas = _gas;
	return !m_ext;
}

bool Executive::create(Address _sender, u256 _endowment, u256 _gasPrice, u256 _gas, bytesConstRef _init, Address _origin)
{
	// We can allow for the reverted state (i.e. that with which m_ext is constructed) to contain the m_newAddress, since
	// we delete it explicitly if we decide we need to revert.
	m_newAddress = right160(sha3(rlpList(_sender, m_s.transactionsFrom(_sender) - 1)));

	// Set up new account...
	m_s.m_cache[m_newAddress] = Account(m_s.balance(m_newAddress) + _endowment, Account::ContractConception);

	// Execute _init.
	m_vm = VMFace::create(VMFace::JIT, _gas).release();
	m_ext = new ExtVM(m_s, m_newAddress, _sender, _origin, _endowment, _gasPrice, bytesConstRef(), _init, m_ms);
	return _init.empty();
}

OnOpFunc Executive::simpleTrace()
{
	return [](uint64_t steps, Instruction inst, bigint newMemSize, bigint gasCost, void* voidVM, void const* voidExt)
	{
		ExtVM const& ext = *(ExtVM const*)voidExt;
		VM& vm = *(VM*)voidVM;	// TODO: Ok for now, because only interpeter/VM supports OnOp callback, but safer solution would be nice

		ostringstream o;
		o << endl << "    STACK" << endl;
		for (auto i: vm.stack())<commit_msg>I don't know what I was thinking: always use interpreter in Executive (for now)<commit_after>/*
	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.

	cpp-ethereum 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 cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/** @file Executive.cpp
 * @author <NAME> <<EMAIL>>
 * @date 2014
 */

#include <boost/timer.hpp>
#include <libdevcore/CommonIO.h>
#include <libevm/VM.h>
#include "Executive.h"
#include "State.h"
#include "ExtVM.h"
using namespace std;
using namespace dev;
using namespace dev::eth;

#define ETH_VMTRACE 1

Executive::~Executive()
{
	// TODO: Make safe.
	delete m_ext;
	delete m_vm;
}

u256 Executive::gasUsed() const
{
	return m_t.gas() - m_endGas;
}

bool Executive::setup(bytesConstRef _rlp)
{
	// Entry point for a user-executed transaction.
	m_t = Transaction(_rlp);

	m_sender = m_t.sender();

	// Avoid invalid transactions.
	auto nonceReq = m_s.transactionsFrom(m_sender);
	if (m_t.nonce() != nonceReq)
	{
		clog(StateDetail) << "Invalid Nonce: Require" << nonceReq << " Got" << m_t.nonce();
		BOOST_THROW_EXCEPTION(InvalidNonce(nonceReq, m_t.nonce()));
	}

	// Don't like transactions whose gas price is too low. NOTE: this won't stay here forever - it's just until we get a proper gas price discovery protocol going.
	if (m_t.gasPrice() < m_s.m_currentBlock.minGasPrice)
	{
		clog(StateDetail) << "Offered gas-price is too low: Require >" << m_s.m_currentBlock.minGasPrice << " Got" << m_t.gasPrice();
		BOOST_THROW_EXCEPTION(GasPriceTooLow());
	}

	// Check gas cost is enough.
	u256 gasCost = m_t.data().size() * c_txDataGas + c_txGas;

	if (m_t.gas() < gasCost)
	{
		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()));
	}

	u256 cost = m_t.value() + m_t.gas() * m_t.gasPrice();

	// Avoid unaffordable transactions.
	if (m_s.balance(m_sender) < cost)
	{
		clog(StateDetail) << "Not enough cash: Require >" << cost << " Got" << m_s.balance(m_sender);
		BOOST_THROW_EXCEPTION(NotEnoughCash() << RequirementError((bigint)cost, (bigint)m_s.balance(m_sender)));
	}

	u256 startGasUsed = m_s.gasUsed();
	if (startGasUsed + 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();
		BOOST_THROW_EXCEPTION(BlockGasLimitReached() << RequirementError((bigint)(m_s.m_currentBlock.gasLimit - startGasUsed), (bigint)m_t.gas()));
	}

	// Increment associated nonce for sender.
	m_s.noteSending(m_sender);

	// Pay...
	clog(StateDetail) << "Paying" << formatBalance(cost) << "from sender (includes" << m_t.gas() << "gas at" << formatBalance(m_t.gasPrice()) << ")";
	m_s.subBalance(m_sender, cost);

	if (m_ms)
	{
		m_ms->from = m_sender;
		m_ms->to = m_t.receiveAddress();
		m_ms->value = m_t.value();
		m_ms->input = m_t.data();
	}

	if (m_t.isCreation())
		return create(m_sender, m_t.value(), m_t.gasPrice(), m_t.gas() - gasCost, &m_t.data(), m_sender);
	else
		return call(m_t.receiveAddress(), m_sender, m_t.value(), m_t.gasPrice(), bytesConstRef(&m_t.data()), m_t.gas() - gasCost, m_sender);
}

bool Executive::call(Address _receiveAddress, Address _senderAddress, u256 _value, u256 _gasPrice, bytesConstRef _data, u256 _gas, Address _originAddress)
{
//	cnote << "Transferring" << formatBalance(_value) << "to receiver.";
	m_s.addBalance(_receiveAddress, _value);

	if (m_s.addressHasCode(_receiveAddress))
	{
		m_vm = VMFace::create(VMFace::Interpreter, _gas).release();
		bytes const& c = m_s.code(_receiveAddress);
		m_ext = new ExtVM(m_s, _receiveAddress, _senderAddress, _originAddress, _value, _gasPrice, _data, &c, m_ms);
	}
	else
		m_endGas = _gas;
	return !m_ext;
}

bool Executive::create(Address _sender, u256 _endowment, u256 _gasPrice, u256 _gas, bytesConstRef _init, Address _origin)
{
	// We can allow for the reverted state (i.e. that with which m_ext is constructed) to contain the m_newAddress, since
	// we delete it explicitly if we decide we need to revert.
	m_newAddress = right160(sha3(rlpList(_sender, m_s.transactionsFrom(_sender) - 1)));

	// Set up new account...
	m_s.m_cache[m_newAddress] = Account(m_s.balance(m_newAddress) + _endowment, Account::ContractConception);

	// Execute _init.
	m_vm = VMFace::create(VMFace::Interpreter, _gas).release();
	m_ext = new ExtVM(m_s, m_newAddress, _sender, _origin, _endowment, _gasPrice, bytesConstRef(), _init, m_ms);
	return _init.empty();
}

OnOpFunc Executive::simpleTrace()
{
	return [](uint64_t steps, Instruction inst, bigint newMemSize, bigint gasCost, void* voidVM, void const* voidExt)
	{
		ExtVM const& ext = *(ExtVM const*)voidExt;
		VM& vm = *(VM*)voidVM;	// TODO: Ok for now, because only interpeter/VM supports OnOp callback, but safer solution would be nice

		ostringstream o;
		o << endl << "    STACK" << endl;
		for (auto i: vm.stack())
{'fraction_non_alphanumeric': 0.13920088381513535, 'fraction_numerical': 0.007917510587368809, 'mean_word_length': 4.687434554973822, 'pattern_counts': {'":': 0, '<': 169, '<?xml version=': 0, '>': 33, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4479836', 'n_tokens_mistral': 4118, 'n_tokens_neox': 3891, 'n_words': 1040}