Note that putting the blockchain (and state etc) on swarm is already planned and thought out.
Integration with IPFS is also in the plan but may have some difficulties.
If and when solved this answers your question.
Purely IPFS solution, full nodes can simply add their chaindata
subdirectory to IPFS, while light clients download by hash, see this reddit post.
Both solutions need to find a way to reach consensus on the current canonical head block('s hash) which is not trivial.
Also both solutions benefit from an incentive scheme which ensures long term redundant storage.
EDIT: actually as Christian Lundkvist points out, this may not answer the question since "The question asks if we can encode the blockchain data structure into the IPFS Merkle DAG using IPFS objects, so that it is completely linked by IPFS hashes"
The answer to that is that it is easy with swarm manifest trie and a little unclear to me if it is just as easy in IPFS or not
Your example shows storing an IPFS identity using it's alphanumeric encoding (Qm...
), which is the same Base58 encoding that Bitcoin uses. However, what it's representing at its core is a number (the hash). Storing the identifier in the Base58 format needs to be a String because it includes letters (and what actually gets saved is the ASCII code for each alphanumeric character in the identifier). That means you need 46 bytes to store QmWmyoMoctfbAaiEs2G46gpeUmhqFRDW6KWo64y5r581Vz
from your example.
However, that identifier can also be expressed in hexadecimal as 12207D5A99F603F231D53A4F39D1521F98D2E8BB279CF29BEBFD0687DC98458E7F89
, which is only 34 bytes long (takes 68 characters to write out in hexadecimal, since every two characters in hex is a byte of data).
But, both of those are greater than 32 bytes, which is the max fixed-size byte array, so they're going to need to use a dynamically-sized byte array to store (bytes
or string
, both of which are expensive, as you noted).
BUT, that IPFS hash is actually two concatenated pieces. It's a multihash identifier, so the first two bytes indicate the hash function being used and the size. 0x12
is sha2, 0x20
is 256-bits long. Currently, that's the only format IPFS uses, so you could just chop off the first two bytes, which leaves you with a 32-byte value, which is small enough to fit in a bytes32
fixed-size byte array, and you save some space there (and when retrieving either your contract can re-attach 0x1220
to the front of it, or your clients need to be smart enough to do that after retrieving the value).
If you want to make sure your code is future-proof, though, you probably want to save that hash function code and size, which you could combine with the hash as a struct:
struct Multihash {
bytes32 hash
uint8 hash_function
uint8 size
}
That will work with any multihash format, as long as size
is less than or equal to 32 (any bigger and the actual payload won't fit in the hash
property). This struct will take two storage slots (two 32-byte chunks) to store, since the two uint8
pieces can be put in one slot. You could also add up to 30 bytes of additional data to this struct without taking any more storage cost.
Best Answer
When storing data on the Ethereum blockchain, each computation task has a cost (in gas unit) and you usually want to reduce as much as possible the cost of the transaction for your application.
You want to store an IPFS hash (or Multihash) (or CID) like QmWATWQ7fVPP2EFGu71UkfnqhYXDYH566qy47CnJDgvs8u in a smart contract
First: Read this to understand multihash
Here is three solutions to store an IPFS hash with the gas cost associated.
Assuming gasPrice: 20 000 000 000 (wei)
1. Store it as a String
Smart contract:
Truffle Test:
Result:
2. Store it as a struct
Smart contract:
Truffle Test:
Result:
3. Store it in the event log
Smart contract:
Truffle Test:
Result:
As you can see, each solution work, the only difference is the gas cost of the transaction for storing an IPFS hash in the Blockchain.
You can find the code here (Truffle project)