зеркало из https://github.com/microsoft/eEVM.git
Abstract account (#49)
* Initial implementation of abstract Account * Update samples * Simplify API * Remove incorrect comment * Simplify further - common implementation of pay_to * Add libfmt license notice * Merge fixups * Disable automatic nonce-increment pending further investigation * Allow nonce to be set in constructor * Remove unnecessary methods from abstract interfaces
This commit is contained in:
Родитель
5f73998ac0
Коммит
36ca7e32ea
|
@ -45,7 +45,6 @@ set(EEVM_INCLUDE_DIRS
|
||||||
)
|
)
|
||||||
|
|
||||||
set(EEVM_CORE_SRCS
|
set(EEVM_CORE_SRCS
|
||||||
src/account.cpp
|
|
||||||
src/disassembler.cpp
|
src/disassembler.cpp
|
||||||
src/processor.cpp
|
src/processor.cpp
|
||||||
src/stack.cpp
|
src/stack.cpp
|
||||||
|
@ -54,6 +53,7 @@ set(EEVM_CORE_SRCS
|
||||||
)
|
)
|
||||||
|
|
||||||
set(EEVM_SIMPLE_SRCS
|
set(EEVM_SIMPLE_SRCS
|
||||||
|
src/simple/simpleaccount.cpp
|
||||||
src/simple/simpleglobalstate.cpp
|
src/simple/simpleglobalstate.cpp
|
||||||
src/simple/simplestorage.cpp
|
src/simple/simplestorage.cpp
|
||||||
)
|
)
|
||||||
|
|
|
@ -2,56 +2,66 @@
|
||||||
// Licensed under the MIT License.
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "address.h"
|
#include "address.h"
|
||||||
#include "bigint.h"
|
#include "bigint.h"
|
||||||
#include "storage.h"
|
#include "exception.h"
|
||||||
#include "util.h"
|
|
||||||
|
|
||||||
#include <nlohmann/json.hpp>
|
|
||||||
|
|
||||||
namespace eevm
|
namespace eevm
|
||||||
{
|
{
|
||||||
using Code = std::vector<uint8_t>;
|
using Code = std::vector<uint8_t>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract interface for interacting with EVM accounts
|
||||||
|
*/
|
||||||
struct Account
|
struct Account
|
||||||
{
|
{
|
||||||
Address address = {};
|
using Nonce = size_t;
|
||||||
uint64_t nonce = {};
|
|
||||||
uint256_t balance = {};
|
|
||||||
Code code = {};
|
|
||||||
|
|
||||||
Account() = default;
|
virtual ~Account() {}
|
||||||
Account(
|
|
||||||
const Address& address, const uint256_t& balance, const Code& code) :
|
|
||||||
address(address),
|
|
||||||
nonce(0),
|
|
||||||
balance(balance),
|
|
||||||
code(code)
|
|
||||||
{}
|
|
||||||
|
|
||||||
Account(
|
virtual Address get_address() const = 0;
|
||||||
const Address& address,
|
|
||||||
uint64_t nonce,
|
|
||||||
const uint256_t& balance,
|
|
||||||
const Code& code) :
|
|
||||||
address(address),
|
|
||||||
nonce(nonce),
|
|
||||||
balance(balance),
|
|
||||||
code(code)
|
|
||||||
{}
|
|
||||||
|
|
||||||
bool has_code() const;
|
virtual uint256_t get_balance() const = 0;
|
||||||
void set_code(Code&& code_);
|
virtual void set_balance(const uint256_t& b) = 0;
|
||||||
|
|
||||||
void pay(const uint256_t& amount);
|
virtual void pay_to(Account& other, const uint256_t& amount)
|
||||||
void pay(Account& r, const uint256_t& amount);
|
{
|
||||||
|
const auto this_balance = get_balance();
|
||||||
|
if (amount > this_balance)
|
||||||
|
{
|
||||||
|
throw Exception(
|
||||||
|
Exception::Type::outOfFunds,
|
||||||
|
"Insufficient funds to pay " + to_hex_str(amount) + " to " +
|
||||||
|
to_hex_str(other.get_address()) + " (from " +
|
||||||
|
to_hex_str(get_address()) + ", current balance " +
|
||||||
|
to_hex_str(this_balance) + ")");
|
||||||
|
}
|
||||||
|
|
||||||
bool operator==(const Account& that) const;
|
const auto other_balance = other.get_balance();
|
||||||
|
const auto proposed_balance = other_balance + amount;
|
||||||
|
if (proposed_balance < other_balance)
|
||||||
|
{
|
||||||
|
throw Exception(
|
||||||
|
Exception::Type::overflow,
|
||||||
|
"Overflow while attempting to pay " + to_hex_str(amount) + " to " +
|
||||||
|
to_hex_str(other.get_address()) + " (current balance " +
|
||||||
|
to_hex_str(other_balance) + ") from " + to_hex_str(get_address()));
|
||||||
|
}
|
||||||
|
|
||||||
friend void to_json(nlohmann::json&, const Account&);
|
set_balance(this_balance - amount);
|
||||||
friend void from_json(const nlohmann::json&, Account&);
|
other.set_balance(proposed_balance);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Nonce get_nonce() const = 0;
|
||||||
|
virtual void increment_nonce() = 0;
|
||||||
|
|
||||||
|
virtual Code get_code() const = 0;
|
||||||
|
virtual void set_code(Code&& code) = 0;
|
||||||
|
|
||||||
|
virtual bool has_code()
|
||||||
|
{
|
||||||
|
return !get_code().empty();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
} // namespace evm
|
||||||
void to_json(nlohmann::json&, const Account&);
|
|
||||||
void from_json(const nlohmann::json&, Account&);
|
|
||||||
} // namespace eevm
|
|
||||||
|
|
|
@ -17,6 +17,7 @@ namespace eevm
|
||||||
outOfBounds,
|
outOfBounds,
|
||||||
outOfGas,
|
outOfGas,
|
||||||
outOfFunds,
|
outOfFunds,
|
||||||
|
overflow,
|
||||||
illegalInstruction,
|
illegalInstruction,
|
||||||
notImplemented
|
notImplemented
|
||||||
};
|
};
|
||||||
|
|
|
@ -21,8 +21,10 @@ namespace eevm
|
||||||
|
|
||||||
template <
|
template <
|
||||||
typename T,
|
typename T,
|
||||||
typename = std::enable_if_t<std::is_base_of<Storage, T>::value>>
|
typename U,
|
||||||
AccountState(std::pair<Account, T>& p) : acc(p.first), st(p.second)
|
typename = std::enable_if_t<std::is_base_of<Account, T>::value>,
|
||||||
|
typename = std::enable_if_t<std::is_base_of<Storage, U>::value>>
|
||||||
|
AccountState(std::pair<T, U>& p) : acc(p.first), st(p.second)
|
||||||
{}
|
{}
|
||||||
AccountState(Account& acc, Storage& st) : acc(acc), st(st) {}
|
AccountState(Account& acc, Storage& st) : acc(acc), st(st) {}
|
||||||
};
|
};
|
||||||
|
@ -32,7 +34,6 @@ namespace eevm
|
||||||
*/
|
*/
|
||||||
struct GlobalState
|
struct GlobalState
|
||||||
{
|
{
|
||||||
virtual bool exists(const Address& addr) = 0;
|
|
||||||
virtual void remove(const Address& addr) = 0;
|
virtual void remove(const Address& addr) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -43,8 +44,6 @@ namespace eevm
|
||||||
virtual AccountState create(
|
virtual AccountState create(
|
||||||
const Address& addr, const uint256_t& balance, const Code& code) = 0;
|
const Address& addr, const uint256_t& balance, const Code& code) = 0;
|
||||||
|
|
||||||
virtual size_t num_accounts() = 0;
|
|
||||||
|
|
||||||
virtual const Block& get_current_block() = 0;
|
virtual const Block& get_current_block() = 0;
|
||||||
virtual uint256_t get_block_hash(uint8_t offset) = 0;
|
virtual uint256_t get_block_hash(uint8_t offset) = 0;
|
||||||
};
|
};
|
||||||
|
|
|
@ -22,10 +22,10 @@ namespace eevm
|
||||||
|
|
||||||
struct ExecResult
|
struct ExecResult
|
||||||
{
|
{
|
||||||
ExitReason er;
|
ExitReason er = {};
|
||||||
Exception::Type ex;
|
Exception::Type ex = {};
|
||||||
std::string exmsg;
|
std::string exmsg = {};
|
||||||
std::vector<uint8_t> output;
|
std::vector<uint8_t> output = {};
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "eEVM/account.h"
|
||||||
|
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
|
namespace eevm
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Simple implementation of Account
|
||||||
|
*/
|
||||||
|
class SimpleAccount : public Account
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
Address address = {};
|
||||||
|
uint256_t balance = {};
|
||||||
|
Code code = {};
|
||||||
|
Nonce nonce = {};
|
||||||
|
|
||||||
|
public:
|
||||||
|
SimpleAccount() = default;
|
||||||
|
|
||||||
|
SimpleAccount(const Address& a, const uint256_t& b, const Code& c) :
|
||||||
|
address(a),
|
||||||
|
balance(b),
|
||||||
|
code(c),
|
||||||
|
nonce(0)
|
||||||
|
{}
|
||||||
|
|
||||||
|
SimpleAccount(
|
||||||
|
const Address& a, const uint256_t& b, const Code& c, Nonce n) :
|
||||||
|
address(a),
|
||||||
|
balance(b),
|
||||||
|
code(c),
|
||||||
|
nonce(n)
|
||||||
|
{}
|
||||||
|
|
||||||
|
virtual Address get_address() const override;
|
||||||
|
void set_address(const Address& a);
|
||||||
|
|
||||||
|
virtual uint256_t get_balance() const override;
|
||||||
|
virtual void set_balance(const uint256_t& b) override;
|
||||||
|
|
||||||
|
virtual Nonce get_nonce() const override;
|
||||||
|
void set_nonce(Nonce n);
|
||||||
|
virtual void increment_nonce() override;
|
||||||
|
|
||||||
|
virtual Code get_code() const override;
|
||||||
|
virtual void set_code(Code&& c) override;
|
||||||
|
virtual bool has_code() override;
|
||||||
|
|
||||||
|
bool operator==(const Account&) const;
|
||||||
|
|
||||||
|
friend void to_json(nlohmann::json&, const SimpleAccount&);
|
||||||
|
friend void from_json(const nlohmann::json&, SimpleAccount&);
|
||||||
|
};
|
||||||
|
|
||||||
|
void to_json(nlohmann::json&, const SimpleAccount&);
|
||||||
|
void from_json(const nlohmann::json&, SimpleAccount&);
|
||||||
|
} // namespace eevm
|
|
@ -4,7 +4,8 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "eEVM/globalstate.h"
|
#include "eEVM/globalstate.h"
|
||||||
#include "simplestorage.h"
|
#include "eEVM/simple/simpleaccount.h"
|
||||||
|
#include "eEVM/simple/simplestorage.h"
|
||||||
|
|
||||||
namespace eevm
|
namespace eevm
|
||||||
{
|
{
|
||||||
|
@ -13,24 +14,26 @@ namespace eevm
|
||||||
*/
|
*/
|
||||||
class SimpleGlobalState : public GlobalState
|
class SimpleGlobalState : public GlobalState
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
using StateEntry = std::pair<SimpleAccount, SimpleStorage>;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Block currentBlock;
|
Block currentBlock;
|
||||||
|
|
||||||
protected:
|
std::map<Address, StateEntry> accounts;
|
||||||
std::map<uint256_t, std::pair<Account, SimpleStorage>> accounts;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SimpleGlobalState() = default;
|
SimpleGlobalState() = default;
|
||||||
explicit SimpleGlobalState(Block b) : currentBlock(std::move(b)) {}
|
explicit SimpleGlobalState(Block b) : currentBlock(std::move(b)) {}
|
||||||
|
|
||||||
virtual bool exists(const Address& addr) override;
|
|
||||||
virtual void remove(const Address& addr) override;
|
virtual void remove(const Address& addr) override;
|
||||||
|
|
||||||
AccountState get(const Address& addr) override;
|
AccountState get(const Address& addr) override;
|
||||||
AccountState create(
|
AccountState create(
|
||||||
const Address& addr, const uint256_t& balance, const Code& code) override;
|
const Address& addr, const uint256_t& balance, const Code& code) override;
|
||||||
|
|
||||||
size_t num_accounts() override;
|
bool exists(const Address& addr);
|
||||||
|
size_t num_accounts();
|
||||||
|
|
||||||
virtual const Block& get_current_block() override;
|
virtual const Block& get_current_block() override;
|
||||||
virtual uint256_t get_block_hash(uint8_t offset) override;
|
virtual uint256_t get_block_hash(uint8_t offset) override;
|
||||||
|
@ -39,7 +42,7 @@ namespace eevm
|
||||||
* For tests which require some initial state, allow manual insertion of
|
* For tests which require some initial state, allow manual insertion of
|
||||||
* pre-constructed accounts
|
* pre-constructed accounts
|
||||||
*/
|
*/
|
||||||
void insert(std::pair<Account, SimpleStorage> p);
|
void insert(const StateEntry& e);
|
||||||
|
|
||||||
friend void to_json(nlohmann::json&, const SimpleGlobalState&);
|
friend void to_json(nlohmann::json&, const SimpleGlobalState&);
|
||||||
friend void from_json(const nlohmann::json&, SimpleGlobalState&);
|
friend void from_json(const nlohmann::json&, SimpleGlobalState&);
|
||||||
|
|
|
@ -22,7 +22,7 @@ namespace eevm
|
||||||
|
|
||||||
void store(const uint256_t& key, const uint256_t& value) override;
|
void store(const uint256_t& key, const uint256_t& value) override;
|
||||||
uint256_t load(const uint256_t& key) override;
|
uint256_t load(const uint256_t& key) override;
|
||||||
bool exists(const uint256_t& key) override;
|
bool exists(const uint256_t& key);
|
||||||
bool remove(const uint256_t& key) override;
|
bool remove(const uint256_t& key) override;
|
||||||
|
|
||||||
bool operator==(const SimpleStorage& that) const;
|
bool operator==(const SimpleStorage& that) const;
|
||||||
|
@ -30,6 +30,7 @@ namespace eevm
|
||||||
friend void to_json(nlohmann::json&, const SimpleStorage&);
|
friend void to_json(nlohmann::json&, const SimpleStorage&);
|
||||||
friend void from_json(const nlohmann::json&, SimpleStorage&);
|
friend void from_json(const nlohmann::json&, SimpleStorage&);
|
||||||
};
|
};
|
||||||
|
|
||||||
void to_json(nlohmann::json& j, const SimpleStorage& s);
|
void to_json(nlohmann::json& j, const SimpleStorage& s);
|
||||||
void from_json(const nlohmann::json& j, SimpleStorage& s);
|
void from_json(const nlohmann::json& j, SimpleStorage& s);
|
||||||
} // namespace eevm
|
} // namespace eevm
|
||||||
|
|
|
@ -15,7 +15,6 @@ namespace eevm
|
||||||
{
|
{
|
||||||
virtual void store(const uint256_t& key, const uint256_t& value) = 0;
|
virtual void store(const uint256_t& key, const uint256_t& value) = 0;
|
||||||
virtual uint256_t load(const uint256_t& key) = 0;
|
virtual uint256_t load(const uint256_t& key) = 0;
|
||||||
virtual bool exists(const uint256_t& key) = 0;
|
|
||||||
virtual bool remove(const uint256_t& key) = 0;
|
virtual bool remove(const uint256_t& key) = 0;
|
||||||
virtual ~Storage() {}
|
virtual ~Storage() {}
|
||||||
};
|
};
|
||||||
|
|
|
@ -120,9 +120,9 @@ eevm::Address deploy_erc20_contract(
|
||||||
|
|
||||||
// Result of running the compiled constructor is the code that should be the
|
// Result of running the compiled constructor is the code that should be the
|
||||||
// contract's body (constructor will also have setup contract's Storage)
|
// contract's body (constructor will also have setup contract's Storage)
|
||||||
contract.acc.code = result;
|
contract.acc.set_code(std::move(result));
|
||||||
|
|
||||||
return contract.acc.address;
|
return contract.acc.get_address();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the total token supply by calling totalSupply on the contract_address
|
// Get the total token supply by calling totalSupply on the contract_address
|
||||||
|
|
|
@ -120,7 +120,7 @@ int main(int argc, char** argv)
|
||||||
std::cout << fmt::format(
|
std::cout << fmt::format(
|
||||||
"Address {} contains the following bytecode:\n {}",
|
"Address {} contains the following bytecode:\n {}",
|
||||||
eevm::to_checksum_address(to),
|
eevm::to_checksum_address(to),
|
||||||
eevm::to_hex_string(contract.acc.code))
|
eevm::to_hex_string(contract.acc.get_code()))
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,75 +0,0 @@
|
||||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
||||||
// Licensed under the MIT License.
|
|
||||||
|
|
||||||
#include "eEVM/account.h"
|
|
||||||
|
|
||||||
#include "eEVM/exception.h"
|
|
||||||
|
|
||||||
#include <ostream>
|
|
||||||
#include <type_traits>
|
|
||||||
|
|
||||||
namespace eevm
|
|
||||||
{
|
|
||||||
bool Account::has_code() const
|
|
||||||
{
|
|
||||||
return code.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Account::set_code(Code&& code_)
|
|
||||||
{
|
|
||||||
// Only set code when it hasn't been set yet
|
|
||||||
if (has_code())
|
|
||||||
return;
|
|
||||||
|
|
||||||
code = code_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Account::pay(const uint256_t& amount)
|
|
||||||
{
|
|
||||||
if (amount > balance)
|
|
||||||
throw Exception(
|
|
||||||
Exception::Type::outOfFunds,
|
|
||||||
"Insufficient funds to pay (" + to_hex_str(amount) + " > " +
|
|
||||||
to_hex_str(balance) + ")");
|
|
||||||
|
|
||||||
balance -= amount;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Account::pay(Account& r, const uint256_t& amount)
|
|
||||||
{
|
|
||||||
pay(amount);
|
|
||||||
r.balance += amount;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Account::operator==(const Account& that) const
|
|
||||||
{
|
|
||||||
return address == that.address && nonce == that.nonce &&
|
|
||||||
balance == that.balance && code == that.code;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline std::ostream& operator<<(std::ostream& os, const Account& a)
|
|
||||||
{
|
|
||||||
os << nlohmann::json(a).dump(2);
|
|
||||||
return os;
|
|
||||||
}
|
|
||||||
|
|
||||||
void to_json(nlohmann::json& j, const Account& a)
|
|
||||||
{
|
|
||||||
j["address"] = address_to_hex_string(a.address);
|
|
||||||
j["balance"] = a.balance;
|
|
||||||
j["nonce"] = to_hex_string(a.nonce);
|
|
||||||
j["code"] = to_hex_string(a.code);
|
|
||||||
}
|
|
||||||
|
|
||||||
void from_json(const nlohmann::json& j, Account& a)
|
|
||||||
{
|
|
||||||
if (j.find("address") != j.end())
|
|
||||||
assign_j(a.address, j["address"]);
|
|
||||||
if (j.find("balance") != j.end())
|
|
||||||
assign_j(a.balance, j["balance"]);
|
|
||||||
if (j.find("nonce") != j.end())
|
|
||||||
assign_j(a.nonce, to_uint64(j["nonce"]));
|
|
||||||
if (j.find("code") != j.end())
|
|
||||||
assign_j(a.code, to_bytes(j["code"]));
|
|
||||||
}
|
|
||||||
} // namespace eevm
|
|
|
@ -36,12 +36,10 @@ namespace eevm
|
||||||
class Program
|
class Program
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
const vector<uint8_t>& code;
|
const vector<uint8_t> code;
|
||||||
const set<uint64_t> jump_dests;
|
const set<uint64_t> jump_dests;
|
||||||
|
|
||||||
Program(const vector<uint8_t>& code) :
|
Program(vector<uint8_t>&& c) : code(c), jump_dests(compute_jump_dests(code))
|
||||||
code(code),
|
|
||||||
jump_dests(compute_jump_dests(code))
|
|
||||||
{}
|
{}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -191,7 +189,14 @@ namespace eevm
|
||||||
};
|
};
|
||||||
|
|
||||||
push_context(
|
push_context(
|
||||||
caller, callee, move(input), callee.acc.code, call_value, rh, hh, eh);
|
caller,
|
||||||
|
callee,
|
||||||
|
move(input),
|
||||||
|
callee.acc.get_code(),
|
||||||
|
call_value,
|
||||||
|
rh,
|
||||||
|
hh,
|
||||||
|
eh);
|
||||||
|
|
||||||
// run
|
// run
|
||||||
while (ctxt->get_pc() < ctxt->prog.code.size())
|
while (ctxt->get_pc() < ctxt->prog.code.size())
|
||||||
|
@ -653,7 +658,8 @@ namespace eevm
|
||||||
"Unknown/unsupported Opcode: 0x{:02x}", int{get_op()})
|
"Unknown/unsupported Opcode: 0x{:02x}", int{get_op()})
|
||||||
<< endl;
|
<< endl;
|
||||||
err << fmt::format(
|
err << fmt::format(
|
||||||
" in contract {}", to_checksum_address(ctxt->as.acc.address))
|
" in contract {}",
|
||||||
|
to_checksum_address(ctxt->as.acc.get_address()))
|
||||||
<< endl;
|
<< endl;
|
||||||
err << fmt::format(" called by {}", to_checksum_address(ctxt->caller))
|
err << fmt::format(" called by {}", to_checksum_address(ctxt->caller))
|
||||||
<< endl;
|
<< endl;
|
||||||
|
@ -988,17 +994,18 @@ namespace eevm
|
||||||
|
|
||||||
void extcodesize()
|
void extcodesize()
|
||||||
{
|
{
|
||||||
ctxt->s.push(gs.get(pop_addr(ctxt->s)).acc.code.size());
|
ctxt->s.push(gs.get(pop_addr(ctxt->s)).acc.get_code().size());
|
||||||
}
|
}
|
||||||
|
|
||||||
void extcodecopy()
|
void extcodecopy()
|
||||||
{
|
{
|
||||||
copy_mem(ctxt->mem, gs.get(pop_addr(ctxt->s)).acc.code, Opcode::STOP);
|
copy_mem(
|
||||||
|
ctxt->mem, gs.get(pop_addr(ctxt->s)).acc.get_code(), Opcode::STOP);
|
||||||
}
|
}
|
||||||
|
|
||||||
void codesize()
|
void codesize()
|
||||||
{
|
{
|
||||||
ctxt->s.push(ctxt->acc.code.size());
|
ctxt->s.push(ctxt->acc.get_code().size());
|
||||||
}
|
}
|
||||||
|
|
||||||
void calldataload()
|
void calldataload()
|
||||||
|
@ -1036,13 +1043,13 @@ namespace eevm
|
||||||
|
|
||||||
void address()
|
void address()
|
||||||
{
|
{
|
||||||
ctxt->s.push(ctxt->acc.address);
|
ctxt->s.push(ctxt->acc.get_address());
|
||||||
}
|
}
|
||||||
|
|
||||||
void balance()
|
void balance()
|
||||||
{
|
{
|
||||||
decltype(auto) acc = gs.get(pop_addr(ctxt->s)).acc;
|
decltype(auto) acc = gs.get(pop_addr(ctxt->s)).acc;
|
||||||
ctxt->s.push(acc.balance);
|
ctxt->s.push(acc.get_balance());
|
||||||
}
|
}
|
||||||
|
|
||||||
void origin()
|
void origin()
|
||||||
|
@ -1102,7 +1109,7 @@ namespace eevm
|
||||||
topics[i] = ctxt->s.pop();
|
topics[i] = ctxt->s.pop();
|
||||||
|
|
||||||
tx.log_handler.handle(
|
tx.log_handler.handle(
|
||||||
{ctxt->acc.address, copy_from_mem(offset, size), topics});
|
{ctxt->acc.get_address(), copy_from_mem(offset, size), topics});
|
||||||
}
|
}
|
||||||
|
|
||||||
void blockhash()
|
void blockhash()
|
||||||
|
@ -1184,8 +1191,9 @@ namespace eevm
|
||||||
|
|
||||||
void destroy()
|
void destroy()
|
||||||
{
|
{
|
||||||
gs.get(pop_addr(ctxt->s)).acc.balance += ctxt->acc.balance;
|
auto recipient = gs.get(pop_addr(ctxt->s));
|
||||||
tx.destroy_list.push_back(ctxt->acc.address);
|
ctxt->acc.pay_to(recipient.acc, ctxt->acc.get_balance());
|
||||||
|
tx.destroy_list.push_back(ctxt->acc.get_address());
|
||||||
stop();
|
stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1194,24 +1202,40 @@ namespace eevm
|
||||||
const auto contractValue = ctxt->s.pop();
|
const auto contractValue = ctxt->s.pop();
|
||||||
const auto offset = ctxt->s.pop64();
|
const auto offset = ctxt->s.pop64();
|
||||||
const auto size = ctxt->s.pop64();
|
const auto size = ctxt->s.pop64();
|
||||||
|
auto initCode = copy_from_mem(offset, size);
|
||||||
ctxt->acc.pay(contractValue);
|
|
||||||
const auto initCode = copy_from_mem(offset, size);
|
|
||||||
|
|
||||||
const auto newAddress =
|
const auto newAddress =
|
||||||
generate_address(ctxt->acc.address, ctxt->acc.nonce);
|
generate_address(ctxt->acc.get_address(), ctxt->acc.get_nonce());
|
||||||
|
|
||||||
|
// For contract accounts, the nonce counts the number of
|
||||||
|
// contract-creations by this account
|
||||||
|
// TODO: Work out why this fails the test cases
|
||||||
|
//ctxt->acc.increment_nonce();
|
||||||
|
|
||||||
decltype(auto) newAcc = gs.create(newAddress, contractValue, {});
|
decltype(auto) newAcc = gs.create(newAddress, contractValue, {});
|
||||||
|
|
||||||
|
// In contract creation, the transaction value is an endowment for the
|
||||||
|
// newly created account
|
||||||
|
ctxt->acc.pay_to(newAcc.acc, contractValue);
|
||||||
|
|
||||||
auto parentContext = ctxt;
|
auto parentContext = ctxt;
|
||||||
auto rh = [&newAcc, parentContext](vector<uint8_t> output) {
|
auto rh = [&newAcc, parentContext](vector<uint8_t> output) {
|
||||||
newAcc.acc.set_code(move(output));
|
newAcc.acc.set_code(move(output));
|
||||||
parentContext->s.push(newAcc.acc.address);
|
parentContext->s.push(newAcc.acc.get_address());
|
||||||
};
|
};
|
||||||
auto hh = [parentContext]() { parentContext->s.push(0); };
|
auto hh = [parentContext]() { parentContext->s.push(0); };
|
||||||
auto eh = [parentContext](const Exception&) { parentContext->s.push(0); };
|
auto eh = [parentContext](const Exception&) { parentContext->s.push(0); };
|
||||||
|
|
||||||
// create new context for init code execution
|
// create new context for init code execution
|
||||||
push_context(ctxt->acc.address, newAcc, {}, initCode, 0, rh, hh, eh);
|
push_context(
|
||||||
|
ctxt->acc.get_address(),
|
||||||
|
newAcc,
|
||||||
|
{},
|
||||||
|
std::move(initCode),
|
||||||
|
0,
|
||||||
|
rh,
|
||||||
|
hh,
|
||||||
|
eh);
|
||||||
}
|
}
|
||||||
|
|
||||||
void call()
|
void call()
|
||||||
|
@ -1234,7 +1258,7 @@ namespace eevm
|
||||||
}
|
}
|
||||||
|
|
||||||
decltype(auto) callee = gs.get(addr);
|
decltype(auto) callee = gs.get(addr);
|
||||||
ctxt->acc.pay(callee.acc, value);
|
ctxt->acc.pay_to(callee.acc, value);
|
||||||
if (!callee.acc.has_code())
|
if (!callee.acc.has_code())
|
||||||
{
|
{
|
||||||
ctxt->s.push(1);
|
ctxt->s.push(1);
|
||||||
|
@ -1257,10 +1281,10 @@ namespace eevm
|
||||||
{
|
{
|
||||||
case Opcode::CALL:
|
case Opcode::CALL:
|
||||||
push_context(
|
push_context(
|
||||||
ctxt->acc.address,
|
ctxt->acc.get_address(),
|
||||||
callee,
|
callee,
|
||||||
move(input),
|
move(input),
|
||||||
callee.acc.code,
|
callee.acc.get_code(),
|
||||||
value,
|
value,
|
||||||
rh,
|
rh,
|
||||||
hh,
|
hh,
|
||||||
|
@ -1268,10 +1292,10 @@ namespace eevm
|
||||||
break;
|
break;
|
||||||
case Opcode::CALLCODE:
|
case Opcode::CALLCODE:
|
||||||
push_context(
|
push_context(
|
||||||
ctxt->acc.address,
|
ctxt->acc.get_address(),
|
||||||
ctxt->as,
|
ctxt->as,
|
||||||
move(input),
|
move(input),
|
||||||
callee.acc.code,
|
callee.acc.get_code(),
|
||||||
value,
|
value,
|
||||||
rh,
|
rh,
|
||||||
hh,
|
hh,
|
||||||
|
@ -1282,7 +1306,7 @@ namespace eevm
|
||||||
ctxt->caller,
|
ctxt->caller,
|
||||||
ctxt->as,
|
ctxt->as,
|
||||||
move(input),
|
move(input),
|
||||||
callee.acc.code,
|
callee.acc.get_code(),
|
||||||
ctxt->call_value,
|
ctxt->call_value,
|
||||||
rh,
|
rh,
|
||||||
hh,
|
hh,
|
||||||
|
|
|
@ -0,0 +1,89 @@
|
||||||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
|
#include "eEVM/simple/simpleaccount.h"
|
||||||
|
|
||||||
|
#include "eEVM/util.h"
|
||||||
|
|
||||||
|
namespace eevm
|
||||||
|
{
|
||||||
|
Address SimpleAccount::get_address() const
|
||||||
|
{
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimpleAccount::set_address(const Address& a)
|
||||||
|
{
|
||||||
|
address = a;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint256_t SimpleAccount::get_balance() const
|
||||||
|
{
|
||||||
|
return balance;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimpleAccount::set_balance(const uint256_t& b)
|
||||||
|
{
|
||||||
|
balance = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
Account::Nonce SimpleAccount::get_nonce() const
|
||||||
|
{
|
||||||
|
return nonce;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimpleAccount::set_nonce(Nonce n)
|
||||||
|
{
|
||||||
|
nonce = n;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimpleAccount::increment_nonce()
|
||||||
|
{
|
||||||
|
++nonce;
|
||||||
|
}
|
||||||
|
|
||||||
|
Code SimpleAccount::get_code() const
|
||||||
|
{
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimpleAccount::set_code(Code&& c)
|
||||||
|
{
|
||||||
|
code = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SimpleAccount::has_code()
|
||||||
|
{
|
||||||
|
return !get_code().empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SimpleAccount::operator==(const Account& a) const
|
||||||
|
{
|
||||||
|
return get_address() == a.get_address() &&
|
||||||
|
get_balance() == a.get_balance() && get_nonce() == a.get_nonce() &&
|
||||||
|
get_code() == a.get_code();
|
||||||
|
}
|
||||||
|
|
||||||
|
void to_json(nlohmann::json& j, const SimpleAccount& a)
|
||||||
|
{
|
||||||
|
j["address"] = address_to_hex_string(a.address);
|
||||||
|
j["balance"] = a.balance;
|
||||||
|
j["nonce"] = to_hex_string(a.nonce);
|
||||||
|
j["code"] = to_hex_string(a.code);
|
||||||
|
}
|
||||||
|
|
||||||
|
void from_json(const nlohmann::json& j, SimpleAccount& a)
|
||||||
|
{
|
||||||
|
if (j.find("address") != j.end())
|
||||||
|
assign_j(a.address, j["address"]);
|
||||||
|
|
||||||
|
if (j.find("balance") != j.end())
|
||||||
|
assign_j(a.balance, j["balance"]);
|
||||||
|
|
||||||
|
if (j.find("nonce") != j.end())
|
||||||
|
assign_j(a.nonce, to_uint64(j["nonce"]));
|
||||||
|
|
||||||
|
if (j.find("code") != j.end())
|
||||||
|
assign_j(a.code, to_bytes(j["code"]));
|
||||||
|
}
|
||||||
|
} // namespace eevm
|
|
@ -5,11 +5,6 @@
|
||||||
|
|
||||||
namespace eevm
|
namespace eevm
|
||||||
{
|
{
|
||||||
bool SimpleGlobalState::exists(const Address& addr)
|
|
||||||
{
|
|
||||||
return accounts.find(addr) != accounts.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SimpleGlobalState::remove(const Address& addr)
|
void SimpleGlobalState::remove(const Address& addr)
|
||||||
{
|
{
|
||||||
accounts.erase(addr);
|
accounts.erase(addr);
|
||||||
|
@ -27,11 +22,14 @@ namespace eevm
|
||||||
AccountState SimpleGlobalState::create(
|
AccountState SimpleGlobalState::create(
|
||||||
const Address& addr, const uint256_t& balance, const Code& code)
|
const Address& addr, const uint256_t& balance, const Code& code)
|
||||||
{
|
{
|
||||||
const auto acc = accounts.emplace(
|
insert({SimpleAccount(addr, balance, code), {}});
|
||||||
addr, std::make_pair(Account(addr, balance, code), SimpleStorage()));
|
|
||||||
assert(acc.second);
|
|
||||||
|
|
||||||
return acc.first->second;
|
return get(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SimpleGlobalState::exists(const Address& addr)
|
||||||
|
{
|
||||||
|
return accounts.find(addr) != accounts.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t SimpleGlobalState::num_accounts()
|
size_t SimpleGlobalState::num_accounts()
|
||||||
|
@ -49,9 +47,11 @@ namespace eevm
|
||||||
return 0u;
|
return 0u;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SimpleGlobalState::insert(std::pair<Account, SimpleStorage> p)
|
void SimpleGlobalState::insert(const StateEntry& p)
|
||||||
{
|
{
|
||||||
accounts.insert(std::make_pair(p.first.address, p));
|
const auto ib = accounts.insert(std::make_pair(p.first.get_address(), p));
|
||||||
|
|
||||||
|
assert(ib.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator==(const SimpleGlobalState& l, const SimpleGlobalState& r)
|
bool operator==(const SimpleGlobalState& l, const SimpleGlobalState& r)
|
||||||
|
@ -74,12 +74,11 @@ namespace eevm
|
||||||
{
|
{
|
||||||
if (j.find("block") != j.end())
|
if (j.find("block") != j.end())
|
||||||
assign_j(a.currentBlock, j["block"]);
|
assign_j(a.currentBlock, j["block"]);
|
||||||
auto acc = j["accounts"].items();
|
|
||||||
for (const auto& it : acc)
|
for (const auto& it : j["accounts"].items())
|
||||||
{
|
{
|
||||||
Address addr = it.value()[0];
|
const auto& v = it.value();
|
||||||
std::pair<Account, SimpleStorage> p = it.value()[1];
|
a.accounts.insert(make_pair(from_hex_str(v[0]), v[1]));
|
||||||
a.accounts.insert(make_pair(addr, p));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // namespace eevm
|
} // namespace eevm
|
||||||
|
|
|
@ -18,12 +18,12 @@ namespace eevm
|
||||||
|
|
||||||
uint64_t to_uint64(const std::string& s)
|
uint64_t to_uint64(const std::string& s)
|
||||||
{
|
{
|
||||||
return strtoull(&s[0], nullptr, 16);
|
return strtoull(s.c_str(), nullptr, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t to_uint64(const nlohmann::json& j)
|
uint64_t to_uint64(const nlohmann::json& j)
|
||||||
{
|
{
|
||||||
return to_uint64(string(j));
|
return to_uint64(j.get<std::string>());
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<uint8_t> to_bytes(const string& _s)
|
vector<uint8_t> to_bytes(const string& _s)
|
||||||
|
|
|
@ -18,11 +18,11 @@ using namespace std;
|
||||||
using namespace eevm;
|
using namespace eevm;
|
||||||
using namespace nlohmann;
|
using namespace nlohmann;
|
||||||
|
|
||||||
pair<Account, SimpleStorage> parseAccount(json::const_iterator& it)
|
SimpleGlobalState::StateEntry parseAccount(json::const_iterator& it)
|
||||||
{
|
{
|
||||||
auto storage = it.value()["storage"];
|
auto storage = it.value()["storage"];
|
||||||
auto account = it.value().get<Account>();
|
auto account = it.value().get<SimpleAccount>();
|
||||||
account.address = from_hex_str(it.key());
|
account.set_address(from_hex_str(it.key()));
|
||||||
return {account, storage};
|
return {account, storage};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,8 +132,8 @@ void run_test_case(
|
||||||
for (auto it = post.value().cbegin(); it != post.value().cend(); it++)
|
for (auto it = post.value().cbegin(); it != post.value().cend(); it++)
|
||||||
{
|
{
|
||||||
const auto expected = parseAccount(it);
|
const auto expected = parseAccount(it);
|
||||||
const auto actual = gs.get(expected.first.address);
|
const auto actual = gs.get(expected.first.get_address());
|
||||||
CHECK(actual.acc == expected.first);
|
CHECK(expected.first == actual.acc);
|
||||||
|
|
||||||
decltype(auto) st = dynamic_cast<SimpleStorage&>(actual.st);
|
decltype(auto) st = dynamic_cast<SimpleStorage&>(actual.st);
|
||||||
CHECK(st == expected.second);
|
CHECK(st == expected.second);
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include "eEVM/disassembler.h"
|
#include "eEVM/disassembler.h"
|
||||||
#include "eEVM/opcode.h"
|
#include "eEVM/opcode.h"
|
||||||
#include "eEVM/processor.h"
|
#include "eEVM/processor.h"
|
||||||
|
#include "eEVM/simple/simpleaccount.h"
|
||||||
#include "eEVM/simple/simpleglobalstate.h"
|
#include "eEVM/simple/simpleglobalstate.h"
|
||||||
#include "eEVM/util.h"
|
#include "eEVM/util.h"
|
||||||
|
|
||||||
|
@ -49,46 +50,48 @@ TEST_CASE(
|
||||||
REQUIRE(j == j2);
|
REQUIRE(j == j2);
|
||||||
}
|
}
|
||||||
|
|
||||||
SUBCASE("Using default Account objects")
|
SUBCASE("Using default SimpleAccount objects")
|
||||||
{
|
{
|
||||||
Account a1;
|
SimpleAccount a1;
|
||||||
nlohmann::json j = a1;
|
nlohmann::json j = a1;
|
||||||
Account a2 = j.get<Account>();
|
SimpleAccount a2 = j.get<SimpleAccount>();
|
||||||
REQUIRE(a1 == a2);
|
REQUIRE(a1 == a2);
|
||||||
}
|
}
|
||||||
|
|
||||||
SUBCASE("Using non-default values for Account")
|
SUBCASE("Using non-default values for SimpleAccount")
|
||||||
{
|
{
|
||||||
Account a1;
|
SimpleAccount a1(
|
||||||
a1.address = from_hex_str("0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6");
|
from_hex_str("0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6"),
|
||||||
a1.nonce = to_uint64(string("0x66"));
|
5678,
|
||||||
|
{0x00, 0x01, 0x10, 0x11},
|
||||||
|
0x66);
|
||||||
nlohmann::json j = a1;
|
nlohmann::json j = a1;
|
||||||
Account a2 = j;
|
SimpleAccount a2 = j;
|
||||||
REQUIRE(a1 == a2);
|
REQUIRE(a1 == a2);
|
||||||
}
|
}
|
||||||
|
|
||||||
SUBCASE("Using partially defined JSON as a source for Account")
|
SUBCASE("Using partially defined JSON as a source for SimpleAccount")
|
||||||
{
|
{
|
||||||
auto test_path = string(test_dir) + "/vmTests.json";
|
auto test_path = string(test_dir) + "/vmTests.json";
|
||||||
const auto j = nlohmann::json::parse(std::ifstream(test_path));
|
const auto j = nlohmann::json::parse(std::ifstream(test_path));
|
||||||
const auto rec = *j["suicide"]["pre"].begin();
|
const auto rec = *j["suicide"]["pre"].begin();
|
||||||
Account a1 = rec.get<Account>();
|
SimpleAccount a1 = rec.get<SimpleAccount>();
|
||||||
nlohmann::json j2 = a1;
|
nlohmann::json j2 = a1;
|
||||||
if (rec.find("balance") != rec.end())
|
if (rec.find("balance") != rec.end())
|
||||||
CHECK(a1.balance == from_hex_str(j2["balance"]));
|
CHECK(a1.get_balance() == from_hex_str(j2["balance"]));
|
||||||
if (rec.find("code") != rec.end())
|
if (rec.find("code") != rec.end())
|
||||||
CHECK(a1.code == to_bytes(j2["code"]));
|
CHECK(a1.get_code() == to_bytes(j2["code"]));
|
||||||
if (rec.find("nonce") != rec.end())
|
if (rec.find("nonce") != rec.end())
|
||||||
CHECK(a1.nonce == to_uint64(j2["nonce"]));
|
CHECK(a1.get_nonce() == to_uint64(j2["nonce"]));
|
||||||
if (rec.find("address") != rec.end())
|
if (rec.find("address") != rec.end())
|
||||||
CHECK(a1.address == from_hex_str(j2["address"]));
|
CHECK(a1.get_address() == from_hex_str(j2["address"]));
|
||||||
}
|
}
|
||||||
|
|
||||||
SUBCASE("Using fully defined JSON as a source for Account")
|
SUBCASE("Using fully defined JSON as a source for SimpleAccount")
|
||||||
{
|
{
|
||||||
auto test_path = string(test_dir) + "/accountFull.json";
|
auto test_path = string(test_dir) + "/accountFull.json";
|
||||||
const auto j = nlohmann::json::parse(std::ifstream(test_path));
|
const auto j = nlohmann::json::parse(std::ifstream(test_path));
|
||||||
Account a1 = j.get<Account>();
|
SimpleAccount a1 = j.get<SimpleAccount>();
|
||||||
nlohmann::json j2 = a1;
|
nlohmann::json j2 = a1;
|
||||||
REQUIRE(j == j2);
|
REQUIRE(j == j2);
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче