Skip to content

Commit 107b86e

Browse files
committed
eof: Support EOF contract creation.
1 parent 5539222 commit 107b86e

27 files changed

+486
-65
lines changed

libevmasm/Assembly.cpp

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1340,10 +1340,15 @@ std::map<uint16_t, uint16_t> Assembly::findReferencedContainers() const
13401340
std::set<uint16_t> referencedSubcontainersIds;
13411341
solAssert(m_subs.size() <= 0x100); // According to EOF spec
13421342

1343-
// TODO: Implement properly when opcodes referring sub containers added.
1344-
for (uint16_t i = 0; i < m_subs.size(); ++i)
1345-
referencedSubcontainersIds.insert(static_cast<uint16_t>(i));
1346-
// END TODO
1343+
for (auto&& codeSection: m_codeSections)
1344+
for (AssemblyItem const& item: codeSection.items)
1345+
if (item.type() == EofCreate || item.type() == ReturnContract)
1346+
{
1347+
solAssert(item.data() <= std::numeric_limits<uint8_t>::max(),
1348+
"Invalid EofCreate/ReturnContract index value.");
1349+
auto const containerId = static_cast<uint16_t>(item.data());
1350+
referencedSubcontainersIds.insert(containerId);
1351+
}
13471352

13481353
std::map<uint16_t, uint16_t> replacements;
13491354
uint8_t nUnreferenced = 0;
@@ -1428,7 +1433,11 @@ LinkerObject const& Assembly::assembleEOF() const
14281433
switch (item.type())
14291434
{
14301435
case Operation:
1431-
solAssert(item.instruction() != Instruction::DATALOADN);
1436+
solAssert(
1437+
item.instruction() != Instruction::DATALOADN &&
1438+
item.instruction() != Instruction::RETURNCONTRACT &&
1439+
item.instruction() != Instruction::EOFCREATE
1440+
);
14321441
solAssert(!(item.instruction() >= Instruction::PUSH0 && item.instruction() <= Instruction::PUSH32));
14331442
ret.bytecode += assembleOperation(item);
14341443
break;
@@ -1442,6 +1451,18 @@ LinkerObject const& Assembly::assembleEOF() const
14421451
ret.linkReferences.insert(linkRef);
14431452
break;
14441453
}
1454+
case EofCreate:
1455+
{
1456+
ret.bytecode.push_back(static_cast<uint8_t>(Instruction::EOFCREATE));
1457+
ret.bytecode.push_back(static_cast<uint8_t>(item.data()));
1458+
break;
1459+
}
1460+
case ReturnContract:
1461+
{
1462+
ret.bytecode.push_back(static_cast<uint8_t>(Instruction::RETURNCONTRACT));
1463+
ret.bytecode.push_back(static_cast<uint8_t>(item.data()));
1464+
break;
1465+
}
14451466
case VerbatimBytecode:
14461467
ret.bytecode += assembleVerbatimBytecode(item);
14471468
break;

libevmasm/Assembly.h

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

105+
AssemblyItem appendEOFCreate(ContainerID _containerId)
106+
{
107+
assertThrow(_containerId < m_subs.size(), AssemblyException, "EOF Create of undefined container");
108+
return append(AssemblyItem::eofCreate(_containerId));
109+
}
110+
AssemblyItem appendReturnContract(ContainerID _containerId)
111+
{
112+
assertThrow(_containerId < m_subs.size(), AssemblyException, "Return undefined container id");
113+
return append(AssemblyItem::returnContract(_containerId));
114+
}
115+
105116
AssemblyItem appendJump() { auto ret = append(newPushTag()); append(Instruction::JUMP); return ret; }
106117
AssemblyItem appendJumpI() { auto ret = append(newPushTag()); append(Instruction::JUMPI); return ret; }
107118
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
@@ -106,6 +106,10 @@ std::pair<std::string, std::string> AssemblyItem::nameAndData(langutil::EVMVersi
106106
return {"AUXDATALOADN", util::toString(data())};
107107
case AuxDataStore:
108108
return {"AUXDATASTORE", ""};
109+
case EofCreate:
110+
return {"EOFCREATE", util::toString(data())};
111+
case ReturnContract:
112+
return {"RETURNCONTRACT", util::toString(data())};
109113
case UndefinedItem:
110114
solAssert(false);
111115
}
@@ -171,6 +175,10 @@ size_t AssemblyItem::bytesRequired(size_t _addressLength, langutil::EVMVersion _
171175
return 1 + 2;
172176
case AuxDataStore:
173177
return 1;
178+
case EofCreate:
179+
return 2;
180+
case ReturnContract:
181+
return 2;
174182
case UndefinedItem:
175183
solAssert(false);
176184
}
@@ -190,6 +198,10 @@ size_t AssemblyItem::arguments() const
190198
return 2;
191199
else if (type() == AuxDataStore)
192200
return 3;
201+
else if (type() == EofCreate)
202+
return 4;
203+
else if (type() == ReturnContract)
204+
return 2;
193205
else
194206
return 0;
195207
}
@@ -216,7 +228,10 @@ size_t AssemblyItem::returnValues() const
216228
return 0;
217229
case VerbatimBytecode:
218230
return std::get<1>(*m_verbatimBytecode);
231+
case ReturnContract:
232+
return 0;
219233
case AuxDataLoadN:
234+
case EofCreate:
220235
return 1;
221236
case AssignImmutable:
222237
case AuxDataStore:
@@ -244,8 +259,10 @@ bool AssemblyItem::canBeFunctional() const
244259
case PushDeployTimeAddress:
245260
case PushImmutable:
246261
case AuxDataLoadN:
262+
case EofCreate:
247263
return true;
248264
case Tag:
265+
case ReturnContract:
249266
return false;
250267
case AssignImmutable:
251268
case VerbatimBytecode:
@@ -355,6 +372,12 @@ std::string AssemblyItem::toAssemblyText(Assembly const& _assembly) const
355372
case AuxDataStore:
356373
text = "auxdatastore()";
357374
break;
375+
case EofCreate:
376+
text = "eofcreate(" + std::to_string(static_cast<size_t>(data())) + ")";
377+
break;
378+
case ReturnContract:
379+
text = "returcontract(" + std::to_string(static_cast<size_t>(data())) + ")";
380+
break;
358381
}
359382
if (m_jumpType == JumpType::IntoFunction || m_jumpType == JumpType::OutOfFunction)
360383
{
@@ -428,6 +451,12 @@ std::ostream& solidity::evmasm::operator<<(std::ostream& _out, AssemblyItem cons
428451
case AuxDataStore:
429452
_out << " AuxDataStore";
430453
break;
454+
case EofCreate:
455+
_out << " EofCreate" << util::toString(_item.data());
456+
break;
457+
case ReturnContract:
458+
_out << " ReturnContract" << util::toString(_item.data());
459+
break;
431460
case UndefinedItem:
432461
_out << " ???";
433462
break;

libevmasm/AssemblyItem.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ enum AssemblyItemType
5757
AuxDataLoadN,
5858
/// Stores value in a memory which which will be appended to EOF data section as static axuliary data.
5959
AuxDataStore,
60+
EofCreate, /// Creates new contract using subcontainer as initcode
61+
ReturnContract, /// Returns new container along (with auxiliary data section) to be deployed
6062
VerbatimBytecode ///< Contains data that is inserted into the bytecode code section without modification.
6163
};
6264

@@ -65,6 +67,7 @@ enum class Precision { Precise , Approximate };
6567
class Assembly;
6668
class AssemblyItem;
6769
using AssemblyItems = std::vector<AssemblyItem>;
70+
using ContainerID = uint8_t;
6871

6972
class AssemblyItem
7073
{
@@ -94,6 +97,15 @@ class AssemblyItem
9497
m_debugData{langutil::DebugData::create()}
9598
{}
9699

100+
static AssemblyItem eofCreate(ContainerID _containerID, langutil::DebugData::ConstPtr _debugData = langutil::DebugData::create())
101+
{
102+
return AssemblyItem(EofCreate, _containerID, _debugData);
103+
}
104+
static AssemblyItem returnContract(ContainerID _containerID, langutil::DebugData::ConstPtr _debugData = langutil::DebugData::create())
105+
{
106+
return AssemblyItem(ReturnContract, _containerID, _debugData);
107+
}
108+
97109
AssemblyItem(AssemblyItem const&) = default;
98110
AssemblyItem(AssemblyItem&&) = default;
99111
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 id with axiliary data section to be deployed.
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: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,7 @@ bool SemanticInformation::altersControlFlow(AssemblyItem const& _item)
293293
case Instruction::STOP:
294294
case Instruction::INVALID:
295295
case Instruction::REVERT:
296+
case Instruction::RETURNCONTRACT:
296297
return true;
297298
default:
298299
return false;
@@ -315,6 +316,7 @@ bool SemanticInformation::terminatesControlFlow(Instruction _instruction)
315316
case Instruction::STOP:
316317
case Instruction::INVALID:
317318
case Instruction::REVERT:
319+
case Instruction::RETURNCONTRACT:
318320
return true;
319321
default:
320322
return false;
@@ -473,6 +475,7 @@ SemanticInformation::Effect SemanticInformation::storage(Instruction _instructio
473475
case Instruction::CREATE:
474476
case Instruction::CREATE2:
475477
case Instruction::SSTORE:
478+
case Instruction::EOFCREATE:
476479
return SemanticInformation::Write;
477480

478481
case Instruction::SLOAD:
@@ -494,6 +497,7 @@ SemanticInformation::Effect SemanticInformation::transientStorage(Instruction _i
494497
case Instruction::CREATE:
495498
case Instruction::CREATE2:
496499
case Instruction::TSTORE:
500+
case Instruction::EOFCREATE:
497501
return SemanticInformation::Write;
498502

499503
case Instruction::TLOAD:
@@ -514,6 +518,7 @@ SemanticInformation::Effect SemanticInformation::otherState(Instruction _instruc
514518
case Instruction::DELEGATECALL:
515519
case Instruction::CREATE:
516520
case Instruction::CREATE2:
521+
case Instruction::EOFCREATE:
517522
case Instruction::SELFDESTRUCT:
518523
case Instruction::STATICCALL: // because it can affect returndatasize
519524
// Strictly speaking, log0, .., log4 writes to the state, but the EVM cannot read it, so they
@@ -588,6 +593,7 @@ bool SemanticInformation::invalidInViewFunctions(Instruction _instruction)
588593
case Instruction::CALL:
589594
case Instruction::CALLCODE:
590595
case Instruction::DELEGATECALL:
596+
case Instruction::EOFCREATE:
591597
case Instruction::CREATE2:
592598
case Instruction::SELFDESTRUCT:
593599
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:

libsolidity/codegen/ir/IRGenerationContext.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,13 +58,15 @@ class IRGenerationContext
5858

5959
IRGenerationContext(
6060
langutil::EVMVersion _evmVersion,
61+
std::optional<uint8_t> _eofVersion,
6162
ExecutionContext _executionContext,
6263
RevertStrings _revertStrings,
6364
std::map<std::string, unsigned> _sourceIndices,
6465
langutil::DebugInfoSelection const& _debugInfoSelection,
6566
langutil::CharStreamProvider const* _soliditySourceProvider
6667
):
6768
m_evmVersion(_evmVersion),
69+
m_eofVersion(_eofVersion),
6870
m_executionContext(_executionContext),
6971
m_revertStrings(_revertStrings),
7072
m_sourceIndices(std::move(_sourceIndices)),
@@ -134,6 +136,7 @@ class IRGenerationContext
134136
YulUtilFunctions utils();
135137

136138
langutil::EVMVersion evmVersion() const { return m_evmVersion; }
139+
std::optional<uint8_t> eofVersion() const { return m_eofVersion; }
137140
ExecutionContext executionContext() const { return m_executionContext; }
138141

139142
void setArithmetic(Arithmetic _value) { m_arithmetic = _value; }
@@ -160,6 +163,7 @@ class IRGenerationContext
160163

161164
private:
162165
langutil::EVMVersion m_evmVersion;
166+
std::optional<uint8_t> m_eofVersion;
163167
ExecutionContext m_executionContext;
164168
RevertStrings m_revertStrings;
165169
std::map<std::string, unsigned> m_sourceIndices;

0 commit comments

Comments
 (0)