Skip to content

Commit

Permalink
Add swarm hash to the end of the bytecode.
Browse files Browse the repository at this point in the history
  • Loading branch information
chriseth committed Dec 1, 2016
1 parent 36c6fe2 commit 91ecc45
Show file tree
Hide file tree
Showing 8 changed files with 20 additions and 23 deletions.
9 changes: 2 additions & 7 deletions docs/miscellaneous.rst
Original file line number Diff line number Diff line change
Expand Up @@ -242,14 +242,10 @@ It can be used to query the compiler version, the sourcecode, the ABI
and NatSpec documentation in order to more safely interact with the contract
and to verify its source code.

The compiler inserts a swarm hash of that file into the bytecode of each
The compiler appends a swarm hash (32 bytes) of that file to the end of the bytecode of each
contract, so that you can retrieve the file in an authenticated way
without having to resort to a centralized data provider.

Specifically, the runtime code for a contract always starts with
``push32 <metadata hash> pop``, so you can take a look at the 32 bytes starting at
the second byte of the code of a contract.

Of course, you have to publish the metadata file to swarm (or some other service)
so that others can access it. The file can be output by using ``solc --metadata``.
It will contain swarm references to the source code, so you have to upload
Expand Down Expand Up @@ -326,8 +322,7 @@ Usage for Automatic Interface Generation and NatSpec

The metadata is used in the following way: A component that wants to interact
with a contract (e.g. mist) retrieves the code of the contract
and from that the first 33 bytes. If the first byte decodes into a PUSH32
instruction, the other 32 bytes are interpreted as the swarm hash of
and from that the last 32 bytes, which are interpreted as the swarm hash of
a file which is then retrieved.
That file is JSON-decoded into a structure like above.

Expand Down
10 changes: 7 additions & 3 deletions libevmasm/Assembly.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,7 @@ LinkerObject const& Assembly::assemble() const
unsigned bytesPerTag = dev::bytesRequired(bytesRequiredForCode);
byte tagPush = (byte)Instruction::PUSH1 - 1 + bytesPerTag;

unsigned bytesRequiredIncludingData = bytesRequiredForCode + 1;
unsigned bytesRequiredIncludingData = bytesRequiredForCode + 1 + m_auxiliaryData.size();
for (auto const& sub: m_subs)
bytesRequiredIncludingData += sub->assemble().bytecode.size();

Expand Down Expand Up @@ -525,8 +525,9 @@ LinkerObject const& Assembly::assemble() const
}
}

if (!dataRef.empty() && !subRef.empty())
ret.bytecode.push_back(0);
// Append a STOP just to be sure.
ret.bytecode.push_back(0);

for (size_t i = 0; i < m_subs.size(); ++i)
{
auto references = subRef.equal_range(i);
Expand Down Expand Up @@ -568,6 +569,9 @@ LinkerObject const& Assembly::assemble() const
}
ret.bytecode += dataItem.second;
}

ret.bytecode += m_auxiliaryData;

for (unsigned pos: sizeRef)
{
bytesRef r(ret.bytecode.data() + pos, bytesPerDataRef);
Expand Down
7 changes: 6 additions & 1 deletion libevmasm/Assembly.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ class Assembly
AssemblyItem appendJumpI(AssemblyItem const& _tag) { auto ret = append(_tag.pushTag()); append(solidity::Instruction::JUMPI); return ret; }
AssemblyItem errorTag() { return AssemblyItem(PushTag, 0); }

/// Appends @a _data literally to the very end of the bytecode.
void appendAuxiliaryDataToEnd(bytes const& _data) { m_auxiliaryData += _data; }

template <class T> Assembly& operator<<(T const& _d) { append(_d); return *this; }
AssemblyItems const& items() const { return m_items; }
AssemblyItem const& back() const { return m_items.back(); }
Expand Down Expand Up @@ -125,10 +128,12 @@ class Assembly
Json::Value createJsonValue(std::string _name, int _begin, int _end, std::string _value = std::string(), std::string _jumpType = std::string()) const;

protected:
// 0 is reserved for exception
/// 0 is reserved for exception
unsigned m_usedTags = 1;
AssemblyItems m_items;
std::map<h256, bytes> m_data;
/// Data that is appended to the very end of the contract.
bytes m_auxiliaryData;
std::vector<std::shared_ptr<Assembly>> m_subs;
std::map<h256, std::string> m_strings;
std::map<h256, std::string> m_libraries; ///< Identifiers of libraries to be linked.
Expand Down
1 change: 1 addition & 0 deletions libsolidity/ast/AST.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ SourceUnitAnnotation& SourceUnit::annotation() const

string Declaration::sourceUnitName() const
{
solAssert(!!m_scope, "");
ASTNode const* scope = m_scope;
while (dynamic_cast<Declaration const*>(scope) && dynamic_cast<Declaration const*>(scope)->m_scope)
scope = dynamic_cast<Declaration const*>(scope)->m_scope;
Expand Down
4 changes: 1 addition & 3 deletions libsolidity/codegen/Compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,14 @@ void Compiler::compileContract(
{
ContractCompiler runtimeCompiler(nullptr, m_runtimeContext, m_optimize);
runtimeCompiler.compileContract(_contract, _contracts);
m_runtimeContext.appendAuxiliaryData(_metadataHash.asBytes());

// This might modify m_runtimeContext because it can access runtime functions at
// creation time.
ContractCompiler creationCompiler(&runtimeCompiler, m_context, m_optimize);
m_runtimeSub = creationCompiler.compileConstructor(_contract, _contracts);

m_context.optimise(m_optimize, m_optimizeRuns);

solAssert(m_runtimeSub != size_t(-1), "");
m_context.injectMetadataHashIntoSub(m_runtimeSub, _metadataHash);
}

void Compiler::compileClone(
Expand Down
7 changes: 0 additions & 7 deletions libsolidity/codegen/CompilerContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -227,13 +227,6 @@ void CompilerContext::injectVersionStampIntoSub(size_t _subIndex)
sub.injectStart(fromBigEndian<u256>(binaryVersion()));
}

void CompilerContext::injectMetadataHashIntoSub(size_t _subIndex, h256 const& _metadataHash)
{
eth::Assembly& sub = m_asm->sub(_subIndex);
sub.injectStart(Instruction::POP);
sub.injectStart(u256(_metadataHash));
}

FunctionDefinition const& CompilerContext::resolveVirtualFunction(
FunctionDefinition const& _function,
vector<ContractDefinition const*>::const_iterator _searchStart
Expand Down
4 changes: 2 additions & 2 deletions libsolidity/codegen/CompilerContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -155,8 +155,8 @@ class CompilerContext
/// Prepends "PUSH <compiler version number> POP"
void injectVersionStampIntoSub(size_t _subIndex);

/// Prepends "PUSH <metadata hash> POP"
void injectMetadataHashIntoSub(size_t _subIndex, h256 const& _metadataHash);
/// Appends arbitrary data to the end of the bytecode.
void appendAuxiliaryData(bytes const& _data) { m_asm->appendAuxiliaryDataToEnd(_data); }

void optimise(bool _fullOptimsation, unsigned _runs = 200) { m_asm->optimise(_fullOptimsation, true, _runs); }

Expand Down
1 change: 1 addition & 0 deletions libsolidity/interface/CompilerStack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,7 @@ Json::Value const& CompilerStack::metadata(Contract const& _contract, Documentat
if (!m_parseSuccessful)
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful."));

solAssert(_contract.contract, "");
std::unique_ptr<Json::Value const>* doc;

// checks wheather we already have the documentation
Expand Down

0 comments on commit 91ecc45

Please sign in to comment.