зеркало из 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
|
||||
src/account.cpp
|
||||
src/disassembler.cpp
|
||||
src/processor.cpp
|
||||
src/stack.cpp
|
||||
|
@ -54,6 +53,7 @@ set(EEVM_CORE_SRCS
|
|||
)
|
||||
|
||||
set(EEVM_SIMPLE_SRCS
|
||||
src/simple/simpleaccount.cpp
|
||||
src/simple/simpleglobalstate.cpp
|
||||
src/simple/simplestorage.cpp
|
||||
)
|
||||
|
|
|
@ -2,56 +2,66 @@
|
|||
// Licensed under the MIT License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "address.h"
|
||||
#include "bigint.h"
|
||||
#include "storage.h"
|
||||
#include "util.h"
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
#include "exception.h"
|
||||
|
||||
namespace eevm
|
||||
{
|
||||
using Code = std::vector<uint8_t>;
|
||||
|
||||
/**
|
||||
* Abstract interface for interacting with EVM accounts
|
||||
*/
|
||||
struct Account
|
||||
{
|
||||
Address address = {};
|
||||
uint64_t nonce = {};
|
||||
uint256_t balance = {};
|
||||
Code code = {};
|
||||
using Nonce = size_t;
|
||||
|
||||
Account() = default;
|
||||
Account(
|
||||
const Address& address, const uint256_t& balance, const Code& code) :
|
||||
address(address),
|
||||
nonce(0),
|
||||
balance(balance),
|
||||
code(code)
|
||||
{}
|
||||
virtual ~Account() {}
|
||||
|
||||
Account(
|
||||
const Address& address,
|
||||
uint64_t nonce,
|
||||
const uint256_t& balance,
|
||||
const Code& code) :
|
||||
address(address),
|
||||
nonce(nonce),
|
||||
balance(balance),
|
||||
code(code)
|
||||
{}
|
||||
virtual Address get_address() const = 0;
|
||||
|
||||
bool has_code() const;
|
||||
void set_code(Code&& code_);
|
||||
virtual uint256_t get_balance() const = 0;
|
||||
virtual void set_balance(const uint256_t& b) = 0;
|
||||
|
||||
void pay(const uint256_t& amount);
|
||||
void pay(Account& r, const uint256_t& amount);
|
||||
virtual void pay_to(Account& other, 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&);
|
||||
friend void from_json(const nlohmann::json&, Account&);
|
||||
set_balance(this_balance - amount);
|
||||
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();
|
||||
}
|
||||
};
|
||||
|
||||
void to_json(nlohmann::json&, const Account&);
|
||||
void from_json(const nlohmann::json&, Account&);
|
||||
} // namespace eevm
|
||||
} // namespace evm
|
||||
|
|
|
@ -17,6 +17,7 @@ namespace eevm
|
|||
outOfBounds,
|
||||
outOfGas,
|
||||
outOfFunds,
|
||||
overflow,
|
||||
illegalInstruction,
|
||||
notImplemented
|
||||
};
|
||||
|
|
|
@ -21,8 +21,10 @@ namespace eevm
|
|||
|
||||
template <
|
||||
typename T,
|
||||
typename = std::enable_if_t<std::is_base_of<Storage, T>::value>>
|
||||
AccountState(std::pair<Account, T>& p) : acc(p.first), st(p.second)
|
||||
typename U,
|
||||
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) {}
|
||||
};
|
||||
|
@ -32,7 +34,6 @@ namespace eevm
|
|||
*/
|
||||
struct GlobalState
|
||||
{
|
||||
virtual bool exists(const Address& addr) = 0;
|
||||
virtual void remove(const Address& addr) = 0;
|
||||
|
||||
/**
|
||||
|
@ -43,8 +44,6 @@ namespace eevm
|
|||
virtual AccountState create(
|
||||
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 uint256_t get_block_hash(uint8_t offset) = 0;
|
||||
};
|
||||
|
|
|
@ -22,10 +22,10 @@ namespace eevm
|
|||
|
||||
struct ExecResult
|
||||
{
|
||||
ExitReason er;
|
||||
Exception::Type ex;
|
||||
std::string exmsg;
|
||||
std::vector<uint8_t> output;
|
||||
ExitReason er = {};
|
||||
Exception::Type ex = {};
|
||||
std::string exmsg = {};
|
||||
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
|
||||
|
||||
#include "eEVM/globalstate.h"
|
||||
#include "simplestorage.h"
|
||||
#include "eEVM/simple/simpleaccount.h"
|
||||
#include "eEVM/simple/simplestorage.h"
|
||||
|
||||
namespace eevm
|
||||
{
|
||||
|
@ -13,24 +14,26 @@ namespace eevm
|
|||
*/
|
||||
class SimpleGlobalState : public GlobalState
|
||||
{
|
||||
public:
|
||||
using StateEntry = std::pair<SimpleAccount, SimpleStorage>;
|
||||
|
||||
private:
|
||||
Block currentBlock;
|
||||
|
||||
protected:
|
||||
std::map<uint256_t, std::pair<Account, SimpleStorage>> accounts;
|
||||
std::map<Address, StateEntry> accounts;
|
||||
|
||||
public:
|
||||
SimpleGlobalState() = default;
|
||||
explicit SimpleGlobalState(Block b) : currentBlock(std::move(b)) {}
|
||||
|
||||
virtual bool exists(const Address& addr) override;
|
||||
virtual void remove(const Address& addr) override;
|
||||
|
||||
AccountState get(const Address& addr) override;
|
||||
AccountState create(
|
||||
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 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
|
||||
* 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 from_json(const nlohmann::json&, SimpleGlobalState&);
|
||||
|
|
|
@ -22,7 +22,7 @@ namespace eevm
|
|||
|
||||
void store(const uint256_t& key, const uint256_t& value) 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 operator==(const SimpleStorage& that) const;
|
||||
|
@ -30,6 +30,7 @@ namespace eevm
|
|||
friend void to_json(nlohmann::json&, const SimpleStorage&);
|
||||
friend void from_json(const nlohmann::json&, SimpleStorage&);
|
||||
};
|
||||
|
||||
void to_json(nlohmann::json& j, const SimpleStorage& s);
|
||||
void from_json(const nlohmann::json& j, SimpleStorage& s);
|
||||
} // namespace eevm
|
||||
|
|
|
@ -15,7 +15,6 @@ namespace eevm
|
|||
{
|
||||
virtual void store(const uint256_t& key, const uint256_t& value) = 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 ~Storage() {}
|
||||
};
|
||||
|
|
|
@ -120,9 +120,9 @@ eevm::Address deploy_erc20_contract(
|
|||
|
||||
// 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.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
|
||||
|
|
|
@ -120,7 +120,7 @@ int main(int argc, char** argv)
|
|||
std::cout << fmt::format(
|
||||
"Address {} contains the following bytecode:\n {}",
|
||||
eevm::to_checksum_address(to),
|
||||
eevm::to_hex_string(contract.acc.code))
|
||||
eevm::to_hex_string(contract.acc.get_code()))
|
||||
<< 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
|
||||
{
|
||||
public:
|
||||
const vector<uint8_t>& code;
|
||||
const vector<uint8_t> code;
|
||||
const set<uint64_t> jump_dests;
|
||||
|
||||
Program(const vector<uint8_t>& code) :
|
||||
code(code),
|
||||
jump_dests(compute_jump_dests(code))
|
||||
Program(vector<uint8_t>&& c) : code(c), jump_dests(compute_jump_dests(code))
|
||||
{}
|
||||
|
||||
private:
|
||||
|
@ -191,7 +189,14 @@ namespace eevm
|
|||
};
|
||||
|
||||
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
|
||||
while (ctxt->get_pc() < ctxt->prog.code.size())
|
||||
|
@ -653,7 +658,8 @@ namespace eevm
|
|||
"Unknown/unsupported Opcode: 0x{:02x}", int{get_op()})
|
||||
<< endl;
|
||||
err << fmt::format(
|
||||
" in contract {}", to_checksum_address(ctxt->as.acc.address))
|
||||
" in contract {}",
|
||||
to_checksum_address(ctxt->as.acc.get_address()))
|
||||
<< endl;
|
||||
err << fmt::format(" called by {}", to_checksum_address(ctxt->caller))
|
||||
<< endl;
|
||||
|
@ -988,17 +994,18 @@ namespace eevm
|
|||
|
||||
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()
|
||||
{
|
||||
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()
|
||||
{
|
||||
ctxt->s.push(ctxt->acc.code.size());
|
||||
ctxt->s.push(ctxt->acc.get_code().size());
|
||||
}
|
||||
|
||||
void calldataload()
|
||||
|
@ -1036,13 +1043,13 @@ namespace eevm
|
|||
|
||||
void address()
|
||||
{
|
||||
ctxt->s.push(ctxt->acc.address);
|
||||
ctxt->s.push(ctxt->acc.get_address());
|
||||
}
|
||||
|
||||
void balance()
|
||||
{
|
||||
decltype(auto) acc = gs.get(pop_addr(ctxt->s)).acc;
|
||||
ctxt->s.push(acc.balance);
|
||||
ctxt->s.push(acc.get_balance());
|
||||
}
|
||||
|
||||
void origin()
|
||||
|
@ -1102,7 +1109,7 @@ namespace eevm
|
|||
topics[i] = ctxt->s.pop();
|
||||
|
||||
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()
|
||||
|
@ -1184,8 +1191,9 @@ namespace eevm
|
|||
|
||||
void destroy()
|
||||
{
|
||||
gs.get(pop_addr(ctxt->s)).acc.balance += ctxt->acc.balance;
|
||||
tx.destroy_list.push_back(ctxt->acc.address);
|
||||
auto recipient = gs.get(pop_addr(ctxt->s));
|
||||
ctxt->acc.pay_to(recipient.acc, ctxt->acc.get_balance());
|
||||
tx.destroy_list.push_back(ctxt->acc.get_address());
|
||||
stop();
|
||||
}
|
||||
|
||||
|
@ -1194,24 +1202,40 @@ namespace eevm
|
|||
const auto contractValue = ctxt->s.pop();
|
||||
const auto offset = ctxt->s.pop64();
|
||||
const auto size = ctxt->s.pop64();
|
||||
|
||||
ctxt->acc.pay(contractValue);
|
||||
const auto initCode = copy_from_mem(offset, size);
|
||||
auto initCode = copy_from_mem(offset, size);
|
||||
|
||||
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, {});
|
||||
|
||||
// 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 rh = [&newAcc, parentContext](vector<uint8_t> 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 eh = [parentContext](const Exception&) { parentContext->s.push(0); };
|
||||
|
||||
// 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()
|
||||
|
@ -1234,7 +1258,7 @@ namespace eevm
|
|||
}
|
||||
|
||||
decltype(auto) callee = gs.get(addr);
|
||||
ctxt->acc.pay(callee.acc, value);
|
||||
ctxt->acc.pay_to(callee.acc, value);
|
||||
if (!callee.acc.has_code())
|
||||
{
|
||||
ctxt->s.push(1);
|
||||
|
@ -1257,10 +1281,10 @@ namespace eevm
|
|||
{
|
||||
case Opcode::CALL:
|
||||
push_context(
|
||||
ctxt->acc.address,
|
||||
ctxt->acc.get_address(),
|
||||
callee,
|
||||
move(input),
|
||||
callee.acc.code,
|
||||
callee.acc.get_code(),
|
||||
value,
|
||||
rh,
|
||||
hh,
|
||||
|
@ -1268,10 +1292,10 @@ namespace eevm
|
|||
break;
|
||||
case Opcode::CALLCODE:
|
||||
push_context(
|
||||
ctxt->acc.address,
|
||||
ctxt->acc.get_address(),
|
||||
ctxt->as,
|
||||
move(input),
|
||||
callee.acc.code,
|
||||
callee.acc.get_code(),
|
||||
value,
|
||||
rh,
|
||||
hh,
|
||||
|
@ -1282,7 +1306,7 @@ namespace eevm
|
|||
ctxt->caller,
|
||||
ctxt->as,
|
||||
move(input),
|
||||
callee.acc.code,
|
||||
callee.acc.get_code(),
|
||||
ctxt->call_value,
|
||||
rh,
|
||||
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
|
||||
{
|
||||
bool SimpleGlobalState::exists(const Address& addr)
|
||||
{
|
||||
return accounts.find(addr) != accounts.end();
|
||||
}
|
||||
|
||||
void SimpleGlobalState::remove(const Address& addr)
|
||||
{
|
||||
accounts.erase(addr);
|
||||
|
@ -27,11 +22,14 @@ namespace eevm
|
|||
AccountState SimpleGlobalState::create(
|
||||
const Address& addr, const uint256_t& balance, const Code& code)
|
||||
{
|
||||
const auto acc = accounts.emplace(
|
||||
addr, std::make_pair(Account(addr, balance, code), SimpleStorage()));
|
||||
assert(acc.second);
|
||||
insert({SimpleAccount(addr, balance, code), {}});
|
||||
|
||||
return acc.first->second;
|
||||
return get(addr);
|
||||
}
|
||||
|
||||
bool SimpleGlobalState::exists(const Address& addr)
|
||||
{
|
||||
return accounts.find(addr) != accounts.end();
|
||||
}
|
||||
|
||||
size_t SimpleGlobalState::num_accounts()
|
||||
|
@ -49,9 +47,11 @@ namespace eevm
|
|||
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)
|
||||
|
@ -74,12 +74,11 @@ namespace eevm
|
|||
{
|
||||
if (j.find("block") != j.end())
|
||||
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];
|
||||
std::pair<Account, SimpleStorage> p = it.value()[1];
|
||||
a.accounts.insert(make_pair(addr, p));
|
||||
const auto& v = it.value();
|
||||
a.accounts.insert(make_pair(from_hex_str(v[0]), v[1]));
|
||||
}
|
||||
}
|
||||
} // namespace eevm
|
||||
|
|
|
@ -18,12 +18,12 @@ namespace eevm
|
|||
|
||||
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)
|
||||
{
|
||||
return to_uint64(string(j));
|
||||
return to_uint64(j.get<std::string>());
|
||||
}
|
||||
|
||||
vector<uint8_t> to_bytes(const string& _s)
|
||||
|
|
|
@ -18,11 +18,11 @@ using namespace std;
|
|||
using namespace eevm;
|
||||
using namespace nlohmann;
|
||||
|
||||
pair<Account, SimpleStorage> parseAccount(json::const_iterator& it)
|
||||
SimpleGlobalState::StateEntry parseAccount(json::const_iterator& it)
|
||||
{
|
||||
auto storage = it.value()["storage"];
|
||||
auto account = it.value().get<Account>();
|
||||
account.address = from_hex_str(it.key());
|
||||
auto account = it.value().get<SimpleAccount>();
|
||||
account.set_address(from_hex_str(it.key()));
|
||||
return {account, storage};
|
||||
}
|
||||
|
||||
|
@ -132,8 +132,8 @@ void run_test_case(
|
|||
for (auto it = post.value().cbegin(); it != post.value().cend(); it++)
|
||||
{
|
||||
const auto expected = parseAccount(it);
|
||||
const auto actual = gs.get(expected.first.address);
|
||||
CHECK(actual.acc == expected.first);
|
||||
const auto actual = gs.get(expected.first.get_address());
|
||||
CHECK(expected.first == actual.acc);
|
||||
|
||||
decltype(auto) st = dynamic_cast<SimpleStorage&>(actual.st);
|
||||
CHECK(st == expected.second);
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "eEVM/disassembler.h"
|
||||
#include "eEVM/opcode.h"
|
||||
#include "eEVM/processor.h"
|
||||
#include "eEVM/simple/simpleaccount.h"
|
||||
#include "eEVM/simple/simpleglobalstate.h"
|
||||
#include "eEVM/util.h"
|
||||
|
||||
|
@ -49,46 +50,48 @@ TEST_CASE(
|
|||
REQUIRE(j == j2);
|
||||
}
|
||||
|
||||
SUBCASE("Using default Account objects")
|
||||
SUBCASE("Using default SimpleAccount objects")
|
||||
{
|
||||
Account a1;
|
||||
SimpleAccount a1;
|
||||
nlohmann::json j = a1;
|
||||
Account a2 = j.get<Account>();
|
||||
SimpleAccount a2 = j.get<SimpleAccount>();
|
||||
REQUIRE(a1 == a2);
|
||||
}
|
||||
|
||||
SUBCASE("Using non-default values for Account")
|
||||
SUBCASE("Using non-default values for SimpleAccount")
|
||||
{
|
||||
Account a1;
|
||||
a1.address = from_hex_str("0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6");
|
||||
a1.nonce = to_uint64(string("0x66"));
|
||||
SimpleAccount a1(
|
||||
from_hex_str("0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6"),
|
||||
5678,
|
||||
{0x00, 0x01, 0x10, 0x11},
|
||||
0x66);
|
||||
nlohmann::json j = a1;
|
||||
Account a2 = j;
|
||||
SimpleAccount a2 = j;
|
||||
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";
|
||||
const auto j = nlohmann::json::parse(std::ifstream(test_path));
|
||||
const auto rec = *j["suicide"]["pre"].begin();
|
||||
Account a1 = rec.get<Account>();
|
||||
SimpleAccount a1 = rec.get<SimpleAccount>();
|
||||
nlohmann::json j2 = a1;
|
||||
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())
|
||||
CHECK(a1.code == to_bytes(j2["code"]));
|
||||
CHECK(a1.get_code() == to_bytes(j2["code"]));
|
||||
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())
|
||||
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";
|
||||
const auto j = nlohmann::json::parse(std::ifstream(test_path));
|
||||
Account a1 = j.get<Account>();
|
||||
SimpleAccount a1 = j.get<SimpleAccount>();
|
||||
nlohmann::json j2 = a1;
|
||||
REQUIRE(j == j2);
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче