From 48dd3f8993988f6a83ecb0d1a4fbe5eaf78c1bc1 Mon Sep 17 00:00:00 2001 From: valdok Date: Wed, 28 Jun 2023 02:20:18 +0300 Subject: [PATCH] evm WIP(5) --- bvm/evm.cpp | 61 ++++++++++++++----- bvm/evm.h | 38 +++++++++--- bvm/unittest/evm_test.cpp | 122 +++++++++++++++++++++----------------- 3 files changed, 142 insertions(+), 79 deletions(-) diff --git a/bvm/evm.cpp b/bvm/evm.cpp index 86113ed82..471ece94a 100644 --- a/bvm/evm.cpp +++ b/bvm/evm.cpp @@ -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); @@ -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; } @@ -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) @@ -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) @@ -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; } @@ -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) @@ -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); } @@ -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 hp; @@ -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) diff --git a/bvm/evm.h b/bvm/evm.h index 58a05fd59..61da166dc 100644 --- a/bvm/evm.h +++ b/bvm/evm.h @@ -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 @@ -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 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; @@ -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: diff --git a/bvm/unittest/evm_test.cpp b/bvm/unittest/evm_test.cpp index cd460d44c..dc50933c4 100644 --- a/bvm/unittest/evm_test.cpp +++ b/bvm/unittest/evm_test.cpp @@ -70,69 +70,75 @@ namespace beam { struct ContractData :public intrusive::set_base_hook
+ ,public IStorage { ByteBuffer m_Code; std::map m_Vars; - }; - intrusive::multiset_autoclear 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 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(); @@ -140,25 +146,27 @@ namespace beam 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(); @@ -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; }