Skip to content

Commit bc58b12

Browse files
committed
eof: Support EOF contract creation.
1 parent 9c33cb0 commit bc58b12

32 files changed

+633
-104
lines changed

libevmasm/Assembly.cpp

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1335,10 +1335,14 @@ std::map<uint16_t, uint16_t> Assembly::findReferencedContainers() const
13351335
std::set<uint16_t> referencedSubcontainersIds;
13361336
solAssert(m_subs.size() <= 0x100); // According to EOF spec
13371337

1338-
// TODO: Implement properly when opcodes referring sub containers added.
1339-
for (uint16_t i = 0; i < m_subs.size(); ++i)
1340-
referencedSubcontainersIds.insert(static_cast<uint16_t>(i));
1341-
// END TODO
1338+
for (auto&& codeSection: m_codeSections)
1339+
for (AssemblyItem const& item: codeSection.items)
1340+
if (item.type() == EOFCreate || item.type() == ReturnContract)
1341+
{
1342+
solAssert(item.data() <= m_subs.size(), "Invalid subcontainer index.");
1343+
auto const containerId = static_cast<ContainerID>(item.data());
1344+
referencedSubcontainersIds.insert(containerId);
1345+
}
13421346

13431347
std::map<uint16_t, uint16_t> replacements;
13441348
uint8_t nUnreferenced = 0;
@@ -1405,7 +1409,11 @@ LinkerObject const& Assembly::assembleEOF() const
14051409
switch (item.type())
14061410
{
14071411
case Operation:
1408-
solAssert(item.instruction() != Instruction::DATALOADN);
1412+
solAssert(
1413+
item.instruction() != Instruction::DATALOADN &&
1414+
item.instruction() != Instruction::RETURNCONTRACT &&
1415+
item.instruction() != Instruction::EOFCREATE
1416+
);
14091417
solAssert(!(item.instruction() >= Instruction::PUSH0 && item.instruction() <= Instruction::PUSH32));
14101418
ret.bytecode += assembleOperation(item);
14111419
break;
@@ -1419,6 +1427,18 @@ LinkerObject const& Assembly::assembleEOF() const
14191427
ret.linkReferences.insert(linkRef);
14201428
break;
14211429
}
1430+
case EOFCreate:
1431+
{
1432+
ret.bytecode.push_back(static_cast<uint8_t>(Instruction::EOFCREATE));
1433+
ret.bytecode.push_back(static_cast<uint8_t>(item.data()));
1434+
break;
1435+
}
1436+
case ReturnContract:
1437+
{
1438+
ret.bytecode.push_back(static_cast<uint8_t>(Instruction::RETURNCONTRACT));
1439+
ret.bytecode.push_back(static_cast<uint8_t>(item.data()));
1440+
break;
1441+
}
14221442
case VerbatimBytecode:
14231443
ret.bytecode += assembleVerbatimBytecode(item);
14241444
break;

libevmasm/Assembly.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,17 @@ class Assembly
9999
append(AssemblyItem(std::move(_data), _arguments, _returnVariables));
100100
}
101101

102+
AssemblyItem appendEOFCreate(ContainerID _containerId)
103+
{
104+
solAssert(_containerId < m_subs.size(), "EOF Create of undefined container.");
105+
return append(AssemblyItem::eofCreate(_containerId));
106+
}
107+
AssemblyItem appendReturnContract(ContainerID _containerId)
108+
{
109+
solAssert(_containerId < m_subs.size(), "Return undefined container ID.");
110+
return append(AssemblyItem::returnContract(_containerId));
111+
}
112+
102113
AssemblyItem appendJump() { auto ret = append(newPushTag()); append(Instruction::JUMP); return ret; }
103114
AssemblyItem appendJumpI() { auto ret = append(newPushTag()); append(Instruction::JUMPI); return ret; }
104115
AssemblyItem appendJump(AssemblyItem const& _tag) { auto ret = append(_tag.pushTag()); append(Instruction::JUMP); return ret; }

libevmasm/AssemblyItem.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,10 @@ std::pair<std::string, std::string> AssemblyItem::nameAndData(langutil::EVMVersi
104104
return {"VERBATIM", util::toHex(verbatimData())};
105105
case AuxDataLoadN:
106106
return {"AUXDATALOADN", util::toString(data())};
107+
case EOFCreate:
108+
return {"EOFCREATE", util::toString(data())};
109+
case ReturnContract:
110+
return {"RETURNCONTRACT", util::toString(data())};
107111
case UndefinedItem:
108112
solAssert(false);
109113
}
@@ -167,6 +171,10 @@ size_t AssemblyItem::bytesRequired(size_t _addressLength, langutil::EVMVersion _
167171
return std::get<2>(*m_verbatimBytecode).size();
168172
case AuxDataLoadN:
169173
return 1 + 2;
174+
case EOFCreate:
175+
return 2;
176+
case ReturnContract:
177+
return 2;
170178
case UndefinedItem:
171179
solAssert(false);
172180
}
@@ -184,6 +192,10 @@ size_t AssemblyItem::arguments() const
184192
return std::get<0>(*m_verbatimBytecode);
185193
else if (type() == AssignImmutable)
186194
return 2;
195+
else if (type() == EOFCreate)
196+
return 4;
197+
else if (type() == ReturnContract)
198+
return 2;
187199
else
188200
return 0;
189201
}
@@ -210,7 +222,10 @@ size_t AssemblyItem::returnValues() const
210222
return 0;
211223
case VerbatimBytecode:
212224
return std::get<1>(*m_verbatimBytecode);
225+
case ReturnContract:
226+
return 0;
213227
case AuxDataLoadN:
228+
case EOFCreate:
214229
return 1;
215230
case AssignImmutable:
216231
case UndefinedItem:
@@ -237,8 +252,10 @@ bool AssemblyItem::canBeFunctional() const
237252
case PushDeployTimeAddress:
238253
case PushImmutable:
239254
case AuxDataLoadN:
255+
case EOFCreate:
240256
return true;
241257
case Tag:
258+
case ReturnContract:
242259
return false;
243260
case AssignImmutable:
244261
case VerbatimBytecode:
@@ -344,6 +361,12 @@ std::string AssemblyItem::toAssemblyText(Assembly const& _assembly) const
344361
assertThrow(data() <= std::numeric_limits<size_t>::max(), AssemblyException, "Invalid auxdataloadn argument.");
345362
text = "auxdataloadn(" + std::to_string(static_cast<size_t>(data())) + ")";
346363
break;
364+
case EOFCreate:
365+
text = "eofcreate{" + std::to_string(static_cast<size_t>(data())) + "}";
366+
break;
367+
case ReturnContract:
368+
text = "returcontract{" + std::to_string(static_cast<size_t>(data())) + "}";
369+
break;
347370
}
348371
if (m_jumpType == JumpType::IntoFunction || m_jumpType == JumpType::OutOfFunction)
349372
{
@@ -414,6 +437,12 @@ std::ostream& solidity::evmasm::operator<<(std::ostream& _out, AssemblyItem cons
414437
case AuxDataLoadN:
415438
_out << " AuxDataLoadN " << util::toString(_item.data());
416439
break;
440+
case EOFCreate:
441+
_out << " EOFCreate" << util::toString(_item.data());
442+
break;
443+
case ReturnContract:
444+
_out << " ReturnContract" << util::toString(_item.data());
445+
break;
417446
case UndefinedItem:
418447
_out << " ???";
419448
break;

libevmasm/AssemblyItem.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ enum AssemblyItemType
5555
/// Loads 32 bytes from static auxiliary data of EOF data section. The offset does *not* have to be always from the beginning
5656
/// of the data EOF section. More details here: https://github.com/ipsilon/eof/blob/main/spec/eof.md#data-section-lifecycle
5757
AuxDataLoadN,
58+
EOFCreate, ///< Creates new contract using subcontainer as initcode
59+
ReturnContract, ///< Returns new container (with auxiliary data filled in) to be deployed
5860
VerbatimBytecode ///< Contains data that is inserted into the bytecode code section without modification.
5961
};
6062

@@ -63,6 +65,7 @@ enum class Precision { Precise , Approximate };
6365
class Assembly;
6466
class AssemblyItem;
6567
using AssemblyItems = std::vector<AssemblyItem>;
68+
using ContainerID = uint8_t;
6669

6770
class AssemblyItem
6871
{
@@ -92,6 +95,15 @@ class AssemblyItem
9295
m_debugData{langutil::DebugData::create()}
9396
{}
9497

98+
static AssemblyItem eofCreate(ContainerID _containerID, langutil::DebugData::ConstPtr _debugData = langutil::DebugData::create())
99+
{
100+
return AssemblyItem(EOFCreate, _containerID, std::move(_debugData));
101+
}
102+
static AssemblyItem returnContract(ContainerID _containerID, langutil::DebugData::ConstPtr _debugData = langutil::DebugData::create())
103+
{
104+
return AssemblyItem(ReturnContract, _containerID, std::move(_debugData));
105+
}
106+
95107
AssemblyItem(AssemblyItem const&) = default;
96108
AssemblyItem(AssemblyItem&&) = default;
97109
AssemblyItem& operator=(AssemblyItem const&) = default;

libevmasm/Instruction.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,8 @@ std::map<std::string, Instruction> const solidity::evmasm::c_instructions =
169169
{ "LOG3", Instruction::LOG3 },
170170
{ "LOG4", Instruction::LOG4 },
171171
{ "DATALOADN", Instruction::DATALOADN },
172+
{ "EOFCREATE", Instruction::EOFCREATE },
173+
{ "RETURNCONTRACT", Instruction::RETURNCONTRACT },
172174
{ "CREATE", Instruction::CREATE },
173175
{ "CALL", Instruction::CALL },
174176
{ "CALLCODE", Instruction::CALLCODE },
@@ -324,6 +326,8 @@ static std::map<Instruction, InstructionInfo> const c_instructionInfo =
324326
{Instruction::LOG2, {"LOG2", 0, 4, 0, true, Tier::Special}},
325327
{Instruction::LOG3, {"LOG3", 0, 5, 0, true, Tier::Special}},
326328
{Instruction::LOG4, {"LOG4", 0, 6, 0, true, Tier::Special}},
329+
{Instruction::EOFCREATE, {"EOFCREATE", 1, 4, 1, true, Tier::Special}},
330+
{Instruction::RETURNCONTRACT, {"RETURNCONTRACT", 1, 2, 0, true, Tier::Special}},
327331
{Instruction::CREATE, {"CREATE", 0, 3, 1, true, Tier::Special}},
328332
{Instruction::CALL, {"CALL", 0, 7, 1, true, Tier::Special}},
329333
{Instruction::CALLCODE, {"CALLCODE", 0, 7, 1, true, Tier::Special}},

libevmasm/Instruction.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,8 @@ enum class Instruction: uint8_t
183183
LOG4, ///< Makes a log entry; 4 topics.
184184

185185
DATALOADN = 0xd1, ///< load data from EOF data section
186+
EOFCREATE = 0xec, ///< create a new account with associated container code.
187+
RETURNCONTRACT = 0xee, ///< return container to be deployed with axiliary data filled in.
186188
CREATE = 0xf0, ///< create a new account with associated code
187189
CALL, ///< message-call into an account
188190
CALLCODE, ///< message-call with another account's code only

libevmasm/SemanticInformation.cpp

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,34 @@ std::vector<SemanticInformation::Operation> SemanticInformation::readWriteOperat
184184
Operation{Location::TransientStorage, Effect::Read, {}, {}, {}},
185185
Operation{Location::TransientStorage, Effect::Write, {}, {}, {}}
186186
};
187+
case Instruction::EOFCREATE:
188+
return std::vector<Operation>{
189+
Operation{
190+
Location::Memory,
191+
Effect::Read,
192+
2,
193+
3,
194+
{}
195+
},
196+
Operation{Location::Storage, Effect::Read, {}, {}, {}},
197+
Operation{Location::Storage, Effect::Write, {}, {}, {}},
198+
Operation{Location::TransientStorage, Effect::Read, {}, {}, {}},
199+
Operation{Location::TransientStorage, Effect::Write, {}, {}, {}}
200+
};
201+
case Instruction::RETURNCONTRACT:
202+
return std::vector<Operation>{
203+
Operation{
204+
Location::Memory,
205+
Effect::Read,
206+
0,
207+
1,
208+
{}
209+
},
210+
Operation{Location::Storage, Effect::Read, {}, {}, {}},
211+
Operation{Location::Storage, Effect::Write, {}, {}, {}},
212+
Operation{Location::TransientStorage, Effect::Read, {}, {}, {}},
213+
Operation{Location::TransientStorage, Effect::Write, {}, {}, {}}
214+
};
187215
case Instruction::MSIZE:
188216
// This is just to satisfy the assert below.
189217
return std::vector<Operation>{};
@@ -280,8 +308,11 @@ bool SemanticInformation::isJumpInstruction(AssemblyItem const& _item)
280308

281309
bool SemanticInformation::altersControlFlow(AssemblyItem const& _item)
282310
{
283-
if (_item.type() != evmasm::Operation)
311+
if (_item.type() == evmasm::ReturnContract)
312+
return true;
313+
else if (_item.type() != evmasm::Operation)
284314
return false;
315+
285316
switch (_item.instruction())
286317
{
287318
// note that CALL, CALLCODE and CREATE do not really alter the control flow, because we
@@ -293,6 +324,7 @@ bool SemanticInformation::altersControlFlow(AssemblyItem const& _item)
293324
case Instruction::STOP:
294325
case Instruction::INVALID:
295326
case Instruction::REVERT:
327+
case Instruction::RETURNCONTRACT:
296328
return true;
297329
default:
298330
return false;
@@ -301,7 +333,9 @@ bool SemanticInformation::altersControlFlow(AssemblyItem const& _item)
301333

302334
bool SemanticInformation::terminatesControlFlow(AssemblyItem const& _item)
303335
{
304-
if (_item.type() != evmasm::Operation)
336+
if (_item.type() == evmasm::ReturnContract)
337+
return true;
338+
else if (_item.type() != evmasm::Operation)
305339
return false;
306340
return terminatesControlFlow(_item.instruction());
307341
}
@@ -315,6 +349,7 @@ bool SemanticInformation::terminatesControlFlow(Instruction _instruction)
315349
case Instruction::STOP:
316350
case Instruction::INVALID:
317351
case Instruction::REVERT:
352+
case Instruction::RETURNCONTRACT:
318353
return true;
319354
default:
320355
return false;
@@ -337,7 +372,9 @@ bool SemanticInformation::isDeterministic(AssemblyItem const& _item)
337372
{
338373
assertThrow(_item.type() != VerbatimBytecode, AssemblyException, "");
339374

340-
if (_item.type() != evmasm::Operation)
375+
if (_item.type() == evmasm::EOFCreate)
376+
return false;
377+
else if (_item.type() != evmasm::Operation)
341378
return true;
342379

343380
switch (_item.instruction())
@@ -357,6 +394,7 @@ bool SemanticInformation::isDeterministic(AssemblyItem const& _item)
357394
case Instruction::EXTCODEHASH:
358395
case Instruction::RETURNDATACOPY: // depends on previous calls
359396
case Instruction::RETURNDATASIZE:
397+
case Instruction::EOFCREATE:
360398
return false;
361399
default:
362400
return true;
@@ -436,6 +474,8 @@ SemanticInformation::Effect SemanticInformation::memory(Instruction _instruction
436474
case Instruction::LOG2:
437475
case Instruction::LOG3:
438476
case Instruction::LOG4:
477+
case Instruction::EOFCREATE:
478+
case Instruction::RETURNCONTRACT:
439479
return SemanticInformation::Read;
440480

441481
default:
@@ -473,6 +513,8 @@ SemanticInformation::Effect SemanticInformation::storage(Instruction _instructio
473513
case Instruction::CREATE:
474514
case Instruction::CREATE2:
475515
case Instruction::SSTORE:
516+
case Instruction::EOFCREATE:
517+
case Instruction::RETURNCONTRACT:
476518
return SemanticInformation::Write;
477519

478520
case Instruction::SLOAD:
@@ -494,6 +536,8 @@ SemanticInformation::Effect SemanticInformation::transientStorage(Instruction _i
494536
case Instruction::CREATE:
495537
case Instruction::CREATE2:
496538
case Instruction::TSTORE:
539+
case Instruction::EOFCREATE:
540+
case Instruction::RETURNCONTRACT:
497541
return SemanticInformation::Write;
498542

499543
case Instruction::TLOAD:
@@ -514,6 +558,8 @@ SemanticInformation::Effect SemanticInformation::otherState(Instruction _instruc
514558
case Instruction::DELEGATECALL:
515559
case Instruction::CREATE:
516560
case Instruction::CREATE2:
561+
case Instruction::EOFCREATE:
562+
case Instruction::RETURNCONTRACT:
517563
case Instruction::SELFDESTRUCT:
518564
case Instruction::STATICCALL: // because it can affect returndatasize
519565
// Strictly speaking, log0, .., log4 writes to the state, but the EVM cannot read it, so they
@@ -588,6 +634,10 @@ bool SemanticInformation::invalidInViewFunctions(Instruction _instruction)
588634
case Instruction::CALL:
589635
case Instruction::CALLCODE:
590636
case Instruction::DELEGATECALL:
637+
// According to EOF spec https://eips.ethereum.org/EIPS/eip-7620#eofcreate
638+
case Instruction::EOFCREATE:
639+
// According to EOF spec https://eips.ethereum.org/EIPS/eip-7620#returncontract
640+
case Instruction::RETURNCONTRACT:
591641
case Instruction::CREATE2:
592642
case Instruction::SELFDESTRUCT:
593643
return true;

liblangutil/EVMVersion.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ bool EVMVersion::hasOpcode(Instruction _opcode, std::optional<uint8_t> _eofVersi
7777
case Instruction::GAS:
7878
return !_eofVersion.has_value();
7979
// Instructions below available only in EOF
80+
case Instruction::EOFCREATE:
81+
case Instruction::RETURNCONTRACT:
8082
case Instruction::DATALOADN:
8183
return _eofVersion.has_value();
8284
default:

0 commit comments

Comments
 (0)