Skip to content

Commit

Permalink
Merge pull request #6599 from ethereum/ipfsHash
Browse files Browse the repository at this point in the history
Add IPFS hash of source files to metadata.
  • Loading branch information
chriseth authored May 15, 2019
2 parents ca4b1bc + b01a8c5 commit ce19e2e
Show file tree
Hide file tree
Showing 8 changed files with 509 additions and 0 deletions.
3 changes: 3 additions & 0 deletions libdevcore/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,13 @@ set(sources
FixedHash.h
IndentedWriter.cpp
IndentedWriter.h
IpfsHash.cpp
IpfsHash.h
JSON.cpp
JSON.h
Keccak256.cpp
Keccak256.h
picosha2.h
Result.h
StringUtils.cpp
StringUtils.h
Expand Down
1 change: 1 addition & 0 deletions libdevcore/Exceptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ struct Exception: virtual std::exception, virtual boost::exception
DEV_SIMPLE_EXCEPTION(InvalidAddress);
DEV_SIMPLE_EXCEPTION(BadHexCharacter);
DEV_SIMPLE_EXCEPTION(FileError);
DEV_SIMPLE_EXCEPTION(DataTooLong);

// error information to be added to exceptions
using errinfo_invalidSymbol = boost::error_info<struct tag_invalidSymbol, char>;
Expand Down
93 changes: 93 additions & 0 deletions libdevcore/IpfsHash.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/*
This file is part of solidity.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/

#include <libdevcore/IpfsHash.h>

#include <libdevcore/Exceptions.h>
#include <libdevcore/picosha2.h>
#include <libdevcore/CommonData.h>

using namespace std;
using namespace dev;

namespace
{
bytes varintEncoding(size_t _n)
{
bytes encoded;
while (_n > 0x7f)
{
encoded.emplace_back(uint8_t(0x80 | (_n & 0x7f)));
_n >>= 7;
}
encoded.emplace_back(_n);
return encoded;
}

string base58Encode(bytes const& _data)
{
static string const alphabet{"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"};
bigint data(toHex(_data, HexPrefix::Add));
string output;
while (data)
{
output += alphabet[size_t(data % alphabet.size())];
data /= alphabet.size();
}
reverse(output.begin(), output.end());
return output;
}
}

bytes dev::ipfsHash(string _data)
{
if (_data.length() >= 1024 * 256)
BOOST_THROW_EXCEPTION(
DataTooLong() <<
errinfo_comment("Ipfs hash for large (chunked) files not yet implemented.")
);

bytes lengthAsVarint = varintEncoding(_data.size());

bytes protobufEncodedData;
// Type: File
protobufEncodedData += bytes{0x08, 0x02};
if (!_data.empty())
{
// Data (length delimited bytes)
protobufEncodedData += bytes{0x12};
protobufEncodedData += lengthAsVarint;
protobufEncodedData += asBytes(std::move(_data));
}
// filesize: length as varint
protobufEncodedData += bytes{0x18} + lengthAsVarint;

// PBDag:
// Data: (length delimited bytes)
size_t protobufLength = protobufEncodedData.size();
bytes blockData = bytes{0x0a} + varintEncoding(protobufLength) + std::move(protobufEncodedData);
// TODO Handle "large" files with multiple blocks

// Multihash: sha2-256, 256 bits
bytes hash = bytes{0x12, 0x20} + picosha2::hash256(std::move(blockData));
return hash;
}

string dev::ipfsHashBase58(string _data)
{
return base58Encode(ipfsHash(std::move(_data)));
}
37 changes: 37 additions & 0 deletions libdevcore/IpfsHash.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
This file is part of solidity.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/

#pragma once

#include <libdevcore/Common.h>

#include <string>

namespace dev
{

/// Compute the "ipfs hash" of a file with the content @a _data.
/// The output will be the multihash of the UnixFS protobuf encoded data.
/// As hash function it will use sha2-256.
/// The effect is that the hash should be identical to the one produced by
/// the command `ipfs add <filename>`.
bytes ipfsHash(std::string _data);

/// Compute the "ipfs hash" as above, but encoded in base58 as used by ipfs / bitcoin.
std::string ipfsHashBase58(std::string _data);

}
Loading

0 comments on commit ce19e2e

Please sign in to comment.