Skip to content

Commit

Permalink
evm WIP(5)
Browse files Browse the repository at this point in the history
  • Loading branch information
valdok committed Jun 27, 2023
1 parent 52124fd commit 48dd3f8
Show file tree
Hide file tree
Showing 3 changed files with 142 additions and 79 deletions.
61 changes: 45 additions & 16 deletions bvm/evm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,13 @@ struct EvmProcessor::Context :public EvmProcessor::Frame

const Address& get_Caller(EvmProcessor& p);

Frame& get_Prev()
{
auto it = Frame::List::s_iterator_to(*this);
--it;
return *it;
}

uint8_t* get_Memory(const Word& wAddr, uint32_t nSize);
static uint64_t get_MemoryCost(uint32_t nSize);

Expand Down Expand Up @@ -258,13 +265,19 @@ uint64_t EvmProcessor::Context::get_MemoryCost(uint32_t nSize)
return (a * 3) + (a * a / 512);
}

EvmProcessor::Frame& EvmProcessor::PushFrame(const Address& addr)
EvmProcessor::Frame& EvmProcessor::PushFrame(IStorage& s)
{
auto* pF = m_lstFrames.Create_back();
pF->m_Address = addr;
ZeroObject(pF->m_Code);
auto* pF = new Frame(s);
m_lstFrames.push_back(*pF);

Blob code;
s.GetCode(code);
pF->m_Code = code;
pF->m_Code.m_Ip = 0;

ZeroObject(pF->m_Args);
pF->m_Gas = 0;

return *pF;
}

Expand Down Expand Up @@ -541,7 +554,7 @@ OnOpcodeBinary(byte)

OnOpcode(address)
{
m_Stack.Push() = m_Address.ToWord();
m_Stack.Push() = m_Storage.get_Address().ToWord();
}

const EvmProcessor::Address& EvmProcessor::Context::get_Caller(EvmProcessor& p)
Expand All @@ -550,9 +563,7 @@ const EvmProcessor::Address& EvmProcessor::Context::get_Caller(EvmProcessor& p)
if (1u == p.m_lstFrames.size())
return p.m_Caller;

auto it = Frame::List::s_iterator_to(*this);
--it;
return it->m_Address;
return get_Prev().m_Storage.get_Address();
}

OnOpcode(caller)
Expand Down Expand Up @@ -638,7 +649,7 @@ OnOpcode(sload)
{
Word& w = m_Stack.get_At(0);

if (!p.SLoad(w, w))
if (!m_Storage.SLoad(w, w))
w = Zero;
}

Expand All @@ -647,7 +658,7 @@ OnOpcode(sstore)
const Word& w1 = m_Stack.Pop();
const Word& w2 = m_Stack.Pop();

p.SStore(w1, w2);
m_Storage.SStore(w1, w2);
}

void EvmProcessor::Context::Jump(const Word& w)
Expand Down Expand Up @@ -764,6 +775,15 @@ void EvmProcessor::Context::OnFrameDone(EvmProcessor& p, bool bSuccess, bool bHa
else
ZeroObject(p.m_RetVal.m_Blob);

if (m_Creation)
{
m_Storage.SetCode(p.m_RetVal.m_Blob);
ZeroObject(p.m_RetVal.m_Blob);

if (p.m_lstFrames.size() > 1)
get_Prev().m_Gas = m_Gas;
}

p.m_lstFrames.Delete(*this);
}

Expand All @@ -774,15 +794,15 @@ OnOpcode(Return)

OnOpcode(Create2)
{
Blob code;

auto& wValue = m_Stack.Pop();
auto nOffset = WtoU32(m_Stack.Pop());
auto nLength = WtoU32(m_Stack.Pop());
auto& wOffset = m_Stack.Pop();
code.n = WtoU32(m_Stack.Pop());
auto& wSalt = m_Stack.Pop();

wValue;
nOffset;
nLength;
wSalt;
code.p = get_Memory(wOffset, code.n);


// new_address = hash(0xFF, sender, salt, bytecode)
KeccakProcessor<Word::nBits> hp;
Expand All @@ -793,6 +813,15 @@ OnOpcode(Create2)

auto& wRes = m_Stack.Push();
hp >> wRes;
Address::WPad(wRes);

auto& s = p.CreateContractData(Address::W2A(wRes));
s.SetCode(code);

auto& f = p.PushFrame(s);
f.m_Args.m_CallValue = wValue;
f.m_Gas = m_Gas;
f.m_Creation = true;
}

OnOpcode(staticcall)
Expand Down
38 changes: 31 additions & 7 deletions bvm/evm.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,20 @@ namespace beam {
{
typedef uintBig_t<20> Base;

void ToWord(Word& w) const
static void WPad(Word& w)
{
static_assert(Word::nBytes >= nBytes);
memset0(w.m_pData, Word::nBytes - nBytes);
memcpy(w.m_pData + Word::nBytes - nBytes, m_pData, nBytes);
}
static Address& W2A(Word& w)
{
static_assert(Word::nBytes >= nBytes);
return *(Address*) (w.m_pData + Word::nBytes - nBytes);
}

void ToWord(Word& w) const
{
WPad(w);
W2A(w) = *this;
}

Word ToWord() const
Expand Down Expand Up @@ -129,17 +138,32 @@ namespace beam {
Word m_CallValue; // amonth of eth to be received by the caller?
};

struct IStorage
{
virtual const Address& get_Address() = 0;

virtual void SStore(const Word& key, const Word&) = 0;
virtual bool SLoad(const Word& key, Word&) = 0;

virtual void SetCode(const Blob&) = 0;
virtual void GetCode(Blob&) = 0;
};

struct Frame
:public boost::intrusive::list_base_hook<>
{
typedef intrusive::list_autoclear<Frame> List;

Address m_Address;
IStorage& m_Storage;

Frame(IStorage& s) :m_Storage(s) {}

Stack m_Stack;
Memory m_Memory;
Code m_Code;
Args m_Args;
uint64_t m_Gas;
bool m_Creation = false;
};

Frame::List m_lstFrames;
Expand All @@ -166,12 +190,12 @@ namespace beam {
};
#pragma pack (pop)

Frame& PushFrame(const Address&);
Frame& PushFrame(IStorage&);

void RunOnce();

virtual void SStore(const Word& key, const Word&) = 0;
virtual bool SLoad(const Word& key, Word&) = 0;
virtual IStorage* GetContractData(const Address&) = 0;
virtual IStorage& CreateContractData(const Address&) = 0;
virtual void get_ChainID(Word&);

private:
Expand Down
122 changes: 66 additions & 56 deletions bvm/unittest/evm_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,95 +70,103 @@ namespace beam
{
struct ContractData
:public intrusive::set_base_hook<Address>
,public IStorage
{
ByteBuffer m_Code;
std::map<Word, Word> m_Vars;
};

intrusive::multiset_autoclear<ContractData> m_mapContracts;
const Address& get_Address() override
{
return m_Key;
}

ContractData* m_pCurrent = nullptr;
void SStore(const Word& key, const Word& w) override
{
if (w == Zero)
{
auto it = m_Vars.find(key);
if (m_Vars.end() != it)
m_Vars.erase(it);
}
else
m_Vars[key] = w;
}

ContractData& get_Current()
{
assert(!m_lstFrames.empty());
auto& f = m_lstFrames.back();

if (!m_pCurrent || (m_pCurrent->m_Key != f.m_Address))
bool SLoad(const Word& key, Word& w) override
{
auto it = m_mapContracts.find(f.m_Address, ContractData::Comparator());
assert(m_mapContracts.end() != it);
m_pCurrent = &(*it);
auto it = m_Vars.find(key);
if (m_Vars.end() == it)
return false;

w = it->second;
return true;
}

return *m_pCurrent;
}
void SetCode(const Blob& b) override
{
b.Export(m_Code);
}

void SStore(const Word& key, const Word& w) override
{
auto& vars = get_Current().m_Vars;
if (w == Zero)
void GetCode(Blob& b) override
{
auto it = vars.find(key);
if (vars.end() != it)
vars.erase(it);
b = m_Code;
}
else
vars[key] = w;

};

intrusive::multiset_autoclear<ContractData> m_mapContracts;

IStorage* GetContractData(const Address& aContract) override
{
auto it = m_mapContracts.find(aContract, ContractData::Comparator());
return (m_mapContracts.end() == it) ? nullptr : &(*it);
}

bool SLoad(const Word& key, Word& w) override
ContractData& CreateContractDataInternal(const Address& aContract)
{
auto& vars = get_Current().m_Vars;
auto it = vars.find(key);
if (vars.end() == it)
return false;
return *m_mapContracts.Create(aContract);
}

w = it->second;
return true;
virtual IStorage& CreateContractData(const Address& aContract)
{
return CreateContractDataInternal(aContract);
}

void RunFull(const Address& aCaller, const Blob& args)
void RunFull(const Address& aCaller)
{
Reset();
assert(m_pCurrent);
assert(m_lstFrames.empty());
assert(1u == m_lstFrames.size());
auto& f = m_lstFrames.back();

auto& f = PushFrame(m_pCurrent->m_Key);
f.m_Args.m_Buf = args;
f.m_Gas = 1000000000ULL;

if (!m_pCurrent->m_Code.empty())
{
f.m_Code.m_p = &m_pCurrent->m_Code.front();
f.m_Code.m_n = (uint32_t) m_pCurrent->m_Code.size();
}
m_Caller = aCaller;

while (!m_lstFrames.empty())
RunOnce();
}

bool Construct(const Address& aContract, const Address& aCaller, const char* szCode, uint32_t nLenCode, const void* pArg, uint32_t nArg)
{
m_pCurrent = m_mapContracts.Create(aContract);
auto& c = *m_pCurrent;
auto& cd = CreateContractDataInternal(aContract);

uint32_t nSizeCode = nLenCode / 2;
c.m_Code.resize(nSizeCode + nArg);
cd.m_Code.resize(nSizeCode + nArg);
if (nSizeCode)
{
auto ret = uintBigImpl::_Scan(&c.m_Code.front(), szCode, nLenCode);
auto ret = uintBigImpl::_Scan(&cd.m_Code.front(), szCode, nLenCode);
verify_test(ret == nLenCode);
memcpy(&c.m_Code.front() + nSizeCode, pArg, nArg);
memcpy(&cd.m_Code.front() + nSizeCode, pArg, nArg);
}

std::cout << "\nCtor" << std::endl;

RunFull(aCaller, Blob());
if (m_RetVal.m_Success)
m_RetVal.m_Blob.Export(c.m_Code); // save retval as the remaining code, rerun
else
m_mapContracts.Delete(c);
Reset();
auto& f = PushFrame(cd);
f.m_Creation = true;

RunFull(aCaller);

if (!m_RetVal.m_Success)
m_mapContracts.Delete(cd);

Reset();

Expand All @@ -169,13 +177,15 @@ namespace beam
{
std::cout << "\nCalling method " << m.m_Selector << std::endl;

auto it = m_mapContracts.find(aContract, ContractData::Comparator());
if (m_mapContracts.end() == it)
IStorage* pS = GetContractData(aContract);
if (!pS)
return false;

m_pCurrent = &(*it);
Reset();
auto& f = PushFrame(*pS);
f.m_Args.m_Buf = Blob(&m, nSizeMethod);

RunFull(aCaller, Blob(&m, nSizeMethod));
RunFull(aCaller);
return m_RetVal.m_Success;

}
Expand Down

0 comments on commit 48dd3f8

Please sign in to comment.