How ISCN rides on IPFS
Aludirk Wong
Decentralized content registry: expanding IPFS functionality with cosmos based blockchain
Who am I?
What is ISCN?
Why we promote ISCN?
Some use cases that we can think about:
ISCN Specification
Traditional Database vs Blockchain
Traditional Database:
Blockchain:
Only trust the host about the uploader | You know a hash of the uploader |
Who create a record?
Only trust the host about the timestamp | You can check the timestamp from tx |
When the record created?
Only trust the host about the content | You can check the creation data from tx |
What data is registered during creation?
Only trust the host's discipline | Only permissible modification allowed |
Any permissible modification?
Cosmos-based LikeCoin chain
Disadvantage of blockchain
Introducing InterPlanetary File Systems (IPFS)
InterPlanetary Linked Data (IPLD)
Content IDentifier (CID)
<multibase-prefix><cid-version><multicodec-content-type><multihash-content-address>
e.g.: bafybeigghnoq332peebw6yl54biym5lr6ackd7ggro2jvqswbkxirnxawq
ISCN metadata
The following is an ISCN IPLD with CID: z4gAY85sHVv5P1CnxGPPYvL3yFxdZXrJ1j4j8PJLntyPfnbJpwQ
{
"context": "https://iscn.io/schema/iscn-v1",
"id": "1/25G6rDEXF2SVLaqMHjX5jur4nnNFJgGoZvms8Hx8LP2C",
"timestamp": "2020-01-01T12:34:56Z",
"version": 1,
"rights": {
"/": "/ipfs/z4gc5ex1gES8s5vDfVAFXfpvNssKaQ4YKf2agiZN5UDsXDx9QXo"
},
"stakeholders": {
"/": "/ipfs/z4h3dBp1iw52EY8KKUX7kWK6sP7GKfw8AJEnJoqoNtSo6vKJ9wW"
},
"content": {
"/": "/ipfs/z4hviFYTSJE27xnwc8f6XttU6tEbgJqqp7KLvxNfKoPzNvyZJxF"
}
}
IPLD plugin
To let the IPFS know how to handle ISCN IPLD, we need to implement the PluginIPLD interface from IPFS core:
// PluginIPLD is an interface that can be implemented to add handlers for
// for different IPLD formats
type PluginIPLD interface {
Plugin
RegisterBlockDecoders(dec ipld.BlockDecoder) error
RegisterInputEncParsers(iec coredag.InputEncParsers) error
}
IPLD plugin - Registering Decoders
The “RegisterBlockDecoders” will be run when the IPFS startup.
func RegisterBlockDecoders(decoder ipld.BlockDecoder) error {
decoder.Register(0x0264, decodeIscnBlock)
decoder.Register(0x0265, decodeRightsBlock)
decoder.Register(0x0266, decodeStakeholdersBlock)
decoder.Register(0x0267, decodeEntityBLock)
decoder.Register(0x0268, decodeContentBlock)
}
IPLD plugin - Decoding
The main decoding logic:
func DecodeBlock(block blocks.Block) (node.Node, error) {
obj := map[string]interface{}{}
if err := cbor.DecodeInto(block.RawData(), &obj); err != nil {
return nil, err
}
// parse the “obj”
// construct a “node.Node”
n := …
return n, nil
}
Datastore plugin
To let the IPFS know where to retrieve the raw binary data of ISCN IPLD, we need to implement the PluginDatastore interface from IPFS core, and a datastore handler:
// PluginDatastore is an interface that can be implemented to add handlers for
// for different datastores
type PluginDatastore interface {
Plugin
DatastoreTypeName() string
DatastoreConfigParser() fsrepo.ConfigFromMap
}
Datastore plugin - Concept
func isISCN(key ds.Key) (bool, *cid.Cid) {
// convert the key to CID
c, err := dshelp.DsKeyToCid(ds.NewKey(key.BaseNamespace()))
if err != nil {
return false, nil
}
// check if the CID type is one of the ISCN types
return iscn.IsIscnObject(c.Type()), &c
}
func (a *accessor) Get(key ds.Key) (value []byte, err error) {
if ok, cid := isISCN(key); ok {
// call Tendermint RPC endpoint to get chain data for ISCN types
return a.tmGet("/custom/iscn/cid_get", *cid)
}
// get non-chain data through original LevelDB flow, skipping
}
// `GetSize` and `Has` are similar
Demo
Conclusion
By combining LikeCoin chain & IPFS:
Contribution
Reference