mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Add swarm hash to the end of the bytecode.
This commit is contained in:
parent
36c6fe2b69
commit
91ecc4533d
@ -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 NatSpec documentation in order to more safely interact with the contract
|
||||||
and to verify its source code.
|
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
|
contract, so that you can retrieve the file in an authenticated way
|
||||||
without having to resort to a centralized data provider.
|
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)
|
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``.
|
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
|
It will contain swarm references to the source code, so you have to upload
|
||||||
@ -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
|
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
|
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
|
and from that the last 32 bytes, which are interpreted as the swarm hash of
|
||||||
instruction, the other 32 bytes are interpreted as the swarm hash of
|
|
||||||
a file which is then retrieved.
|
a file which is then retrieved.
|
||||||
That file is JSON-decoded into a structure like above.
|
That file is JSON-decoded into a structure like above.
|
||||||
|
|
||||||
|
@ -432,7 +432,7 @@ LinkerObject const& Assembly::assemble() const
|
|||||||
unsigned bytesPerTag = dev::bytesRequired(bytesRequiredForCode);
|
unsigned bytesPerTag = dev::bytesRequired(bytesRequiredForCode);
|
||||||
byte tagPush = (byte)Instruction::PUSH1 - 1 + bytesPerTag;
|
byte tagPush = (byte)Instruction::PUSH1 - 1 + bytesPerTag;
|
||||||
|
|
||||||
unsigned bytesRequiredIncludingData = bytesRequiredForCode + 1;
|
unsigned bytesRequiredIncludingData = bytesRequiredForCode + 1 + m_auxiliaryData.size();
|
||||||
for (auto const& sub: m_subs)
|
for (auto const& sub: m_subs)
|
||||||
bytesRequiredIncludingData += sub->assemble().bytecode.size();
|
bytesRequiredIncludingData += sub->assemble().bytecode.size();
|
||||||
|
|
||||||
@ -525,8 +525,9 @@ LinkerObject const& Assembly::assemble() const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dataRef.empty() && !subRef.empty())
|
// Append a STOP just to be sure.
|
||||||
ret.bytecode.push_back(0);
|
ret.bytecode.push_back(0);
|
||||||
|
|
||||||
for (size_t i = 0; i < m_subs.size(); ++i)
|
for (size_t i = 0; i < m_subs.size(); ++i)
|
||||||
{
|
{
|
||||||
auto references = subRef.equal_range(i);
|
auto references = subRef.equal_range(i);
|
||||||
@ -568,6 +569,9 @@ LinkerObject const& Assembly::assemble() const
|
|||||||
}
|
}
|
||||||
ret.bytecode += dataItem.second;
|
ret.bytecode += dataItem.second;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ret.bytecode += m_auxiliaryData;
|
||||||
|
|
||||||
for (unsigned pos: sizeRef)
|
for (unsigned pos: sizeRef)
|
||||||
{
|
{
|
||||||
bytesRef r(ret.bytecode.data() + pos, bytesPerDataRef);
|
bytesRef r(ret.bytecode.data() + pos, bytesPerDataRef);
|
||||||
|
@ -71,6 +71,9 @@ public:
|
|||||||
AssemblyItem appendJumpI(AssemblyItem const& _tag) { auto ret = append(_tag.pushTag()); append(solidity::Instruction::JUMPI); return ret; }
|
AssemblyItem appendJumpI(AssemblyItem const& _tag) { auto ret = append(_tag.pushTag()); append(solidity::Instruction::JUMPI); return ret; }
|
||||||
AssemblyItem errorTag() { return AssemblyItem(PushTag, 0); }
|
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; }
|
template <class T> Assembly& operator<<(T const& _d) { append(_d); return *this; }
|
||||||
AssemblyItems const& items() const { return m_items; }
|
AssemblyItems const& items() const { return m_items; }
|
||||||
AssemblyItem const& back() const { return m_items.back(); }
|
AssemblyItem const& back() const { return m_items.back(); }
|
||||||
@ -125,10 +128,12 @@ private:
|
|||||||
Json::Value createJsonValue(std::string _name, int _begin, int _end, std::string _value = std::string(), std::string _jumpType = std::string()) const;
|
Json::Value createJsonValue(std::string _name, int _begin, int _end, std::string _value = std::string(), std::string _jumpType = std::string()) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// 0 is reserved for exception
|
/// 0 is reserved for exception
|
||||||
unsigned m_usedTags = 1;
|
unsigned m_usedTags = 1;
|
||||||
AssemblyItems m_items;
|
AssemblyItems m_items;
|
||||||
std::map<h256, bytes> m_data;
|
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::vector<std::shared_ptr<Assembly>> m_subs;
|
||||||
std::map<h256, std::string> m_strings;
|
std::map<h256, std::string> m_strings;
|
||||||
std::map<h256, std::string> m_libraries; ///< Identifiers of libraries to be linked.
|
std::map<h256, std::string> m_libraries; ///< Identifiers of libraries to be linked.
|
||||||
|
@ -65,6 +65,7 @@ SourceUnitAnnotation& SourceUnit::annotation() const
|
|||||||
|
|
||||||
string Declaration::sourceUnitName() const
|
string Declaration::sourceUnitName() const
|
||||||
{
|
{
|
||||||
|
solAssert(!!m_scope, "");
|
||||||
ASTNode const* scope = m_scope;
|
ASTNode const* scope = m_scope;
|
||||||
while (dynamic_cast<Declaration const*>(scope) && dynamic_cast<Declaration 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;
|
scope = dynamic_cast<Declaration const*>(scope)->m_scope;
|
||||||
|
@ -36,6 +36,7 @@ void Compiler::compileContract(
|
|||||||
{
|
{
|
||||||
ContractCompiler runtimeCompiler(nullptr, m_runtimeContext, m_optimize);
|
ContractCompiler runtimeCompiler(nullptr, m_runtimeContext, m_optimize);
|
||||||
runtimeCompiler.compileContract(_contract, _contracts);
|
runtimeCompiler.compileContract(_contract, _contracts);
|
||||||
|
m_runtimeContext.appendAuxiliaryData(_metadataHash.asBytes());
|
||||||
|
|
||||||
// This might modify m_runtimeContext because it can access runtime functions at
|
// This might modify m_runtimeContext because it can access runtime functions at
|
||||||
// creation time.
|
// creation time.
|
||||||
@ -43,9 +44,6 @@ void Compiler::compileContract(
|
|||||||
m_runtimeSub = creationCompiler.compileConstructor(_contract, _contracts);
|
m_runtimeSub = creationCompiler.compileConstructor(_contract, _contracts);
|
||||||
|
|
||||||
m_context.optimise(m_optimize, m_optimizeRuns);
|
m_context.optimise(m_optimize, m_optimizeRuns);
|
||||||
|
|
||||||
solAssert(m_runtimeSub != size_t(-1), "");
|
|
||||||
m_context.injectMetadataHashIntoSub(m_runtimeSub, _metadataHash);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Compiler::compileClone(
|
void Compiler::compileClone(
|
||||||
|
@ -227,13 +227,6 @@ void CompilerContext::injectVersionStampIntoSub(size_t _subIndex)
|
|||||||
sub.injectStart(fromBigEndian<u256>(binaryVersion()));
|
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& CompilerContext::resolveVirtualFunction(
|
||||||
FunctionDefinition const& _function,
|
FunctionDefinition const& _function,
|
||||||
vector<ContractDefinition const*>::const_iterator _searchStart
|
vector<ContractDefinition const*>::const_iterator _searchStart
|
||||||
|
@ -155,8 +155,8 @@ public:
|
|||||||
/// Prepends "PUSH <compiler version number> POP"
|
/// Prepends "PUSH <compiler version number> POP"
|
||||||
void injectVersionStampIntoSub(size_t _subIndex);
|
void injectVersionStampIntoSub(size_t _subIndex);
|
||||||
|
|
||||||
/// Prepends "PUSH <metadata hash> POP"
|
/// Appends arbitrary data to the end of the bytecode.
|
||||||
void injectMetadataHashIntoSub(size_t _subIndex, h256 const& _metadataHash);
|
void appendAuxiliaryData(bytes const& _data) { m_asm->appendAuxiliaryDataToEnd(_data); }
|
||||||
|
|
||||||
void optimise(bool _fullOptimsation, unsigned _runs = 200) { m_asm->optimise(_fullOptimsation, true, _runs); }
|
void optimise(bool _fullOptimsation, unsigned _runs = 200) { m_asm->optimise(_fullOptimsation, true, _runs); }
|
||||||
|
|
||||||
|
@ -375,6 +375,7 @@ Json::Value const& CompilerStack::metadata(Contract const& _contract, Documentat
|
|||||||
if (!m_parseSuccessful)
|
if (!m_parseSuccessful)
|
||||||
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful."));
|
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful."));
|
||||||
|
|
||||||
|
solAssert(_contract.contract, "");
|
||||||
std::unique_ptr<Json::Value const>* doc;
|
std::unique_ptr<Json::Value const>* doc;
|
||||||
|
|
||||||
// checks wheather we already have the documentation
|
// checks wheather we already have the documentation
|
||||||
|
Loading…
Reference in New Issue
Block a user