* 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:
Eddy Ashton 2019-08-23 13:18:25 +01:00 коммит произвёл GitHub
Родитель 5f73998ac0
Коммит 36ca7e32ea
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
18 изменённых файлов: 314 добавлений и 198 удалений

Просмотреть файл

@ -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);
} }