You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
201 lines
5.3 KiB
201 lines
5.3 KiB
#include "sha256.h"
|
|
#include "VirtualMachine.h"
|
|
using namespace std;
|
|
using namespace eth;
|
|
|
|
VirtualMachine::VirtualMachine()
|
|
{
|
|
}
|
|
|
|
VirtualMachine::~VirtualMachine()
|
|
{
|
|
}
|
|
|
|
|
|
void VirtualMachine::go()
|
|
{
|
|
bool stopped = false;
|
|
while (!stopped)
|
|
{
|
|
auto rawInst = m_memory[m_pc];
|
|
if (rawInst > 0xff)
|
|
throw BadInstruction();
|
|
Instruction inst = (Instruction)(uint8_t)rawInst;
|
|
|
|
auto require = [&](uint _n)
|
|
{
|
|
if (m_stack.size() < _n)
|
|
throw StackTooSmall(_n, m_stack.size());
|
|
};
|
|
|
|
switch (inst)
|
|
{
|
|
case Instruction::ADD:
|
|
//pops two items and pushes S[-1] + S[-2] mod 2^256.
|
|
require(2);
|
|
m_stack[m_stack.size() - 2] += m_stack.back();
|
|
m_stack.pop_back();
|
|
break;
|
|
case Instruction::MUL:
|
|
//pops two items and pushes S[-1] * S[-2] mod 2^256.
|
|
require(2);
|
|
m_stack[m_stack.size() - 2] *= m_stack.back();
|
|
m_stack.pop_back();
|
|
break;
|
|
case Instruction::SUB:
|
|
require(2);
|
|
m_stack[m_stack.size() - 2] = m_stack.back() - m_stack[m_stack.size() - 2];
|
|
m_stack.pop_back();
|
|
break;
|
|
case Instruction::DIV:
|
|
require(2);
|
|
m_stack[m_stack.size() - 2] = m_stack.back() / m_stack[m_stack.size() - 2];
|
|
m_stack.pop_back();
|
|
break;
|
|
case Instruction::SDIV:
|
|
require(2);
|
|
(s256&)m_stack[m_stack.size() - 2] = (s256&)m_stack.back() / (s256&)m_stack[m_stack.size() - 2];
|
|
m_stack.pop_back();
|
|
break;
|
|
case Instruction::MOD:
|
|
require(2);
|
|
m_stack[m_stack.size() - 2] = m_stack.back() % m_stack[m_stack.size() - 2];
|
|
m_stack.pop_back();
|
|
break;
|
|
case Instruction::SMOD:
|
|
require(2);
|
|
(s256&)m_stack[m_stack.size() - 2] = (s256&)m_stack.back() % (s256&)m_stack[m_stack.size() - 2];
|
|
m_stack.pop_back();
|
|
break;
|
|
case Instruction::EXP:
|
|
{
|
|
// TODO: better implementation?
|
|
require(2);
|
|
auto n = m_stack.back();
|
|
auto x = m_stack[m_stack.size() - 2];
|
|
m_stack.pop_back();
|
|
for (u256 i = 0; i < x; ++i)
|
|
n *= n;
|
|
m_stack.back() = n;
|
|
break;
|
|
}
|
|
case Instruction::NEG:
|
|
require(1);
|
|
m_stack.back() = ~(m_stack.back() - 1);
|
|
break;
|
|
case Instruction::LT:
|
|
require(2);
|
|
m_stack[m_stack.size() - 2] = m_stack.back() < m_stack[m_stack.size() - 2] ? 1 : 0;
|
|
m_stack.pop_back();
|
|
break;
|
|
case Instruction::LE:
|
|
require(2);
|
|
m_stack[m_stack.size() - 2] = m_stack.back() <= m_stack[m_stack.size() - 2] ? 1 : 0;
|
|
m_stack.pop_back();
|
|
break;
|
|
case Instruction::GT:
|
|
require(2);
|
|
m_stack[m_stack.size() - 2] = m_stack.back() > m_stack[m_stack.size() - 2] ? 1 : 0;
|
|
m_stack.pop_back();
|
|
break;
|
|
case Instruction::GE:
|
|
require(2);
|
|
m_stack[m_stack.size() - 2] = m_stack.back() >= m_stack[m_stack.size() - 2] ? 1 : 0;
|
|
m_stack.pop_back();
|
|
break;
|
|
case Instruction::EQ:
|
|
require(2);
|
|
m_stack[m_stack.size() - 2] = m_stack.back() == m_stack[m_stack.size() - 2] ? 1 : 0;
|
|
m_stack.pop_back();
|
|
break;
|
|
case Instruction::NOT:
|
|
require(1);
|
|
m_stack.back() = m_stack.back() ? 0 : 1;
|
|
m_stack.pop_back();
|
|
break;
|
|
case Instruction::MYADDRESS:
|
|
m_stack.push_back(m_myAddress);
|
|
break;
|
|
case Instruction::TXSENDER:
|
|
m_stack.push_back(m_txSender);
|
|
break;
|
|
case Instruction::TXVALUE:
|
|
m_stack.push_back(m_txValue);
|
|
break;
|
|
case Instruction::TXFEE:
|
|
m_stack.push_back(m_txFee);
|
|
break;
|
|
case Instruction::TXDATAN:
|
|
m_stack.push_back(m_txData.size());
|
|
break;
|
|
case Instruction::TXDATA:
|
|
require(1);
|
|
m_stack.back() = m_stack.back() < m_txData.size() ? m_txData[(uint)m_stack.back()] : 0;
|
|
break;
|
|
case Instruction::BLK_PREVHASH:
|
|
m_stack.push_back(m_previousBlock.hash);
|
|
break;
|
|
case Instruction::BLK_COINBASE:
|
|
m_stack.push_back(m_currentBlock.coinbase);
|
|
break;
|
|
case Instruction::BLK_TIMESTAMP:
|
|
m_stack.push_back(m_currentBlock.timestamp);
|
|
break;
|
|
case Instruction::BLK_NUMBER:
|
|
m_stack.push_back(m_currentBlock.number);
|
|
break;
|
|
case Instruction::BLK_DIFFICULTY:
|
|
m_stack.push_back(m_currentBlock.difficulty);
|
|
break;
|
|
case Instruction::SHA256:
|
|
case Instruction::RIPEMD160:
|
|
{
|
|
uint s = (uint)min(m_stack.back(), (u256)(m_stack.size() - 1) * 32);
|
|
bytes b(s);
|
|
uint i = 0;
|
|
for (; s; s = (s >= 32 ? s - 32 : 0), i += 32)
|
|
{
|
|
m_stack.pop_back();
|
|
u256 v = m_stack.back();
|
|
int sz = (int)min<u256>(32, s) - 1; // sz is one fewer than the number of bytes we're interested in.
|
|
v >>= ((31 - sz) * 8); // kill unused low-order bytes.
|
|
for (int j = 0; j <= sz; ++j, v >>= 8) // cycle through bytes, starting at low-order end.
|
|
b[i + sz - j] = (byte)(v & 0xff); // set each 32-byte (256-bit) chunk in reverse - (i.e. we want to put low-order last).
|
|
}
|
|
if (inst == Instruction::SHA256)
|
|
m_stack.back() = sha256(b);
|
|
else
|
|
m_stack.back() = ripemd160(&b);
|
|
|
|
break;
|
|
}
|
|
case Instruction::ECMUL:
|
|
case Instruction::ECADD:
|
|
case Instruction::ECSIGN:
|
|
case Instruction::ECRECOVER:
|
|
case Instruction::ECVALID:
|
|
case Instruction::PUSH:
|
|
case Instruction::POP:
|
|
case Instruction::DUP:
|
|
case Instruction::DUPN:
|
|
case Instruction::SWAP:
|
|
case Instruction::SWAPN:
|
|
case Instruction::LOAD:
|
|
case Instruction::STORE:
|
|
case Instruction::JMP:
|
|
case Instruction::JMPI:
|
|
case Instruction::IND:
|
|
case Instruction::EXTRO:
|
|
case Instruction::BALANCE:
|
|
case Instruction::MKTX:
|
|
break;
|
|
case Instruction::SUICIDE:
|
|
// TODO: Suicide...
|
|
case Instruction::STOP:
|
|
// TODO: Cleanups...
|
|
return;
|
|
default:
|
|
throw BadInstruction();
|
|
}
|
|
}
|
|
}
|
|
|