BitXID是遵循W3C DID规范的DID框架,可用于快速开发属于自己的DID应用。本文档将介绍BitXID相关功能的使用。
BitXID的主要分为两大模块:账户数字身份模块(Account DID)和链数字身份模块(Chain DID)。前者主要用于构建单链上的账户数字身份,后者主要用于构建跨链网络中的链数字身份。账户数字身份是指基于区块链上的账户地址的数字身份,而链身份是指区块链自己的数字身份。如果您只想在单链上使用DID,则可以只使用Account DID部分功能,如果您想在某个跨链平台上集成数字身份功能,则可以考虑Chain DID + Account DID的组合。
BitXID 支持多种存储方式,给了开发者充足的选择权。BitXID中关于 Account DID 和 Chain DID 两部分功能的设计使得开发者可以实现两种存储类型的DID应用,一种是 InternalDocDB,开发者可以将 DID Doc 存储在链上;另一种是 ExternalDocDB,开发者可以将 DID Doc 存储在链下。
ExternalDocDB 模式的 Chain DID,此处我们以启动一条4节点中继链后在其上初始化ChainDIDRegistry,并对一条单节点应用链进行其链DID相关操作为例。
package main
import (
"bytes"
"crypto/sha256"
"fmt"
"io/ioutil"
"os"
"time"
"github.com/meshplus/bitxid"
"github.com/meshplus/bitxhub-kit/log"
"github.com/meshplus/bitxhub-kit/storage/leveldb"
"github.com/meshplus/bitxhub-model/pb"
)
func main() {
// 构造链身份信息文档 Chain Doc
adminDID := bitxid.DID("did:bitxhub:relayroot:0x00000001")
relaychainDoc := bitxid.ChainDoc{
BasicDoc: bitxid.BasicDoc{
ID: bitxid.DID("did:bitxhub:relayroot:."),
Type: int(bitxid.ChainDIDType),
Created: uint64(time.Now().Second()),
PublicKey: []bitxid.PubKey{
{
ID: "KEY#1",
Type: "secp256k1",
PublicKeyPem: `MIICWjCCAf+gAwIBAgIDDhFLMAoGCCqGSM49BAMCMIGaMQswCQYDVQQGEwJDTjER
MA8GA1UECBMIWmhlSmlhbmcxETAPBgNVBAcTCEhhbmdaaG91MR8wDQYDVQQJEwZz
dHJlZXQwDgYDVQQJEwdhZGRyZXNzMQ8wDQYDVQQREwYzMjQwMDAxDzANBgNVBAoT
BkFnZW5jeTEQMA4GA1UECxMHQml0WEh1YjEQMA4GA1UEAxMHQml0WEh1YjAgFw0y
MDA4MTEwNTA3MTNaGA8yMDcwMDczMDA1MDcxM1owgZkxCzAJBgNVBAYTAkNOMREw
DwYDVQQIEwhaaGVKaWFuZzERMA8GA1UEBxMISGFuZ1pob3UxHzANBgNVBAkTBnN0
cmVldDAOBgNVBAkTB2FkZHJlc3MxDzANBgNVBBETBjMyNDAwMDEOMAwGA1UEChMF
Tm9kZTExEDAOBgNVBAsTB0JpdFhIdWIxEDAOBgNVBAMTB0JpdFhIdWIwWTATBgcq
hkjOPQIBBggqhkjOPQMBBwNCAATgjTYEnavxerFuEKJ8C39QUY12xh/TC2E5V7ni
nmQcOgDDRv5HW4sskTSm/WX2D0BMzwb7XE5ATyoDeM9qcurDozEwLzAOBgNVHQ8B
Af8EBAMCAaYwDwYDVR0lBAgwBgYEVR0lADAMBgNVHRMBAf8EAjAAMAoGCCqGSM49
BAMCA0kAMEYCIQD5Oz1xJvFgzYm/lTzoaO/i0ayPVRgSdBwvK6hEICo5lAIhAMtG
aswjd2wVA4zB5GPEmJ/tvPUnxrlOAU67AQMYR4zf`,
}, {
ID: "KEY#2",
Type: "secp256k1",
PublicKeyPem: `MIICWjCCAf+gAwIBAgIDDhFLMAoGCCqGSM49BAMCMIGaMQswCQYDVQQGEwJDTjER
MA8GA1UECBMIWmhlSmlhbmcxETAPBgNVBAcTCEhhbmdaaG91MR8wDQYDVQQJEwZz
dHJlZXQwDgYDVQQJEwdhZGRyZXNzMQ8wDQYDVQQREwYzMjQwMDAxDzANBgNVBAoT
BkFnZW5jeTEQMA4GA1UECxMHQml0WEh1YjEQMA4GA1UEAxMHQml0WEh1YjAgFw0y
MDA4MTEwNTA3MTNaGA8yMDcwMDczMDA1MDcxM1owgZkxCzAJBgNVBAYTAkNOMREw
DwYDVQQIEwhaaGVKaWFuZzERMA8GA1UEBxMISGFuZ1pob3UxHzANBgNVBAkTBnN0
cmVldDAOBgNVBAkTB2FkZHJlc3MxDzANBgNVBBETBjMyNDAwMDEOMAwGA1UEChMF
Tm9kZTExEDAOBgNVBAsTB0JpdFhIdWIxEDAOBgNVBAMTB0JpdFhIdWIwWTATBgcq
hkjOPQIBBggqhkjOPQMBBwNCAATgjTYEnavxerFuEKJ8C39QUY12xh/TC2E5V7ni
nmQcOgDDRv5HW4sskTSm/WX2D0BMzwb7XE5ATyoDeM9qcurDozEwLzAOBgNVHQ8B
Af8EBAMCAaYwDwYDVR0lBAgwBgYEVR0lADAMBgNVHRMBAf8EAjAAMAoGCCqGSM49
BAMCA0kAMEYCIQD5Oz1xJvFgzYm/lTzoaO/i0ayPVRgSdBwvK6hEICo5lAIhAMtG
aswjd2wVA4zB5GPEmJ/tvPUnxrlOAU67AQMYR4zf`,
}, {
ID: "KEY#3",
Type: "secp256k1",
PublicKeyPem: `MIICWTCCAf+gAwIBAgIDCUHDMAoGCCqGSM49BAMCMIGaMQswCQYDVQQGEwJDTjER
MA8GA1UECBMIWmhlSmlhbmcxETAPBgNVBAcTCEhhbmdaaG91MR8wDQYDVQQJEwZz
dHJlZXQwDgYDVQQJEwdhZGRyZXNzMQ8wDQYDVQQREwYzMjQwMDAxDzANBgNVBAoT
BkFnZW5jeTEQMA4GA1UECxMHQml0WEh1YjEQMA4GA1UEAxMHQml0WEh1YjAgFw0y
MDA4MTEwNTA3MTRaGA8yMDcwMDczMDA1MDcxNFowgZkxCzAJBgNVBAYTAkNOMREw
DwYDVQQIEwhaaGVKaWFuZzERMA8GA1UEBxMISGFuZ1pob3UxHzANBgNVBAkTBnN0
cmVldDAOBgNVBAkTB2FkZHJlc3MxDzANBgNVBBETBjMyNDAwMDEOMAwGA1UEChMF
Tm9kZTMxEDAOBgNVBAsTB0JpdFhIdWIxEDAOBgNVBAMTB0JpdFhIdWIwWTATBgcq
hkjOPQIBBggqhkjOPQMBBwNCAAQ9IPBBKkqSwWkwDdK+ARw2qlBmBD9bF8HJ0z3P
XeKaTmnnEBJu1e0vjHl+uQGBz5x1ulBRVeq4xhmkZtPZByO+ozEwLzAOBgNVHQ8B
Af8EBAMCAaYwDwYDVR0lBAgwBgYEVR0lADAMBgNVHRMBAf8EAjAAMAoGCCqGSM49
BAMCA0gAMEUCIQCMgYSwQ9go1jjAcC4SxpJl4moA8Ba/GEb0qwFPaNmSCwIgDEOo
UpUSNYEQJvahR4BxxVLOBf/CNlKhAGBVNKTccxk`,
}, {
ID: "KEY#4",
Type: "secp256k1",
PublicKeyPem: `MIICWTCCAf+gAwIBAgIDCGR3MAoGCCqGSM49BAMCMIGaMQswCQYDVQQGEwJDTjER
MA8GA1UECBMIWmhlSmlhbmcxETAPBgNVBAcTCEhhbmdaaG91MR8wDQYDVQQJEwZz
dHJlZXQwDgYDVQQJEwdhZGRyZXNzMQ8wDQYDVQQREwYzMjQwMDAxDzANBgNVBAoT
BkFnZW5jeTEQMA4GA1UECxMHQml0WEh1YjEQMA4GA1UEAxMHQml0WEh1YjAgFw0y
MDA4MTEwNTA3MTRaGA8yMDcwMDczMDA1MDcxNFowgZkxCzAJBgNVBAYTAkNOMREw
DwYDVQQIEwhaaGVKaWFuZzERMA8GA1UEBxMISGFuZ1pob3UxHzANBgNVBAkTBnN0
cmVldDAOBgNVBAkTB2FkZHJlc3MxDzANBgNVBBETBjMyNDAwMDEOMAwGA1UEChMF
Tm9kZTQxEDAOBgNVBAsTB0JpdFhIdWIxEDAOBgNVBAMTB0JpdFhIdWIwWTATBgcq
hkjOPQIBBggqhkjOPQMBBwNCAARN1y/FhZpSg1kpXF38szDNRXdPkqoc8oRKdGzv
3HdhtBdUO7jXe2xNaWVtNMGXVo+NuBi5t9qEoo+euxfnjlc9ozEwLzAOBgNVHQ8B
Af8EBAMCAaYwDwYDVR0lBAgwBgYEVR0lADAMBgNVHRMBAf8EAjAAMAoGCCqGSM49
BAMCA0gAMEUCIQCbsG7E158uzqYCzrrnrr2Xsnz7f5cFA2o4SXAF7R/IyAIgSxYS
MGj0g0OBcxJqwTyyvF2FFOhlWjF9nq2eYK/rlzI`,
},
},
Authentication: []bitxid.Auth{{PublicKey: []string{"KEY#1", "KEY#2", "KEY#3", "KEY#4"}, Strategy: "1-of-4"}},
},
}
relaychainDID := relaychainDoc.ID
docBytes, _ := relaychainDoc.Marshal()
relaychainDocAddr := fakeStore(&relaychainDoc) // 假设将Doc进行了存储,返回了存储地址
relaychainDocHash := fakeHash(docBytes) // 假设将Doc进行了哈希,返回了哈希结果
mcaller := bitxid.DID("did:bitxhub:relayroot:0x12345678")
chainDID := bitxid.DID("did:bitxhub:appchain001:.")
appchainDoc := bitxid.ChainDoc{
BasicDoc: bitxid.BasicDoc{
ID: chainDID,
Type: int(bitxid.ChainDIDType),
Created: 1616985208,
PublicKey: []bitxid.PubKey{
{
ID: "KEY#1",
Type: "secp256k1",
PublicKeyPem: `MIICWjCCAf+gAwIBAgIDDhFLMAoGCCqGSM49BAMCMIGaMQswCQYDVQQGEwJDTjER
MA8GA1UECBMIWmhlSmlhbmcxETAPBgNVBAcTCEhhbmdaaG91MR8wDQYDVQQJEwZz
dHJlZXQwDgYDVQQJEwdhZGRyZXNzMQ8wDQYDVQQREwYzMjQwMDAxDzANBgNVBAoT
BkFnZW5jeTEQMA4GA1UECxMHQml0WEh1YjEQMA4GA1UEAxMHQml0WEh1YjAgFw0y
MDA4MTEwNTA3MTNaGA8yMDcwMDczMDA1MDcxM1owgZkxCzAJBgNVBAYTAkNOMREw
DwYDVQQIEwhaaGVKaWFuZzERMA8GA1UEBxMISGFuZ1pob3UxHzANBgNVBAkTBnN0
cmVldDAOBgNVBAkTB2FkZHJlc3MxDzANBgNVBBETBjMyNDAwMDEOMAwGA1UEChMF
Tm9kZTExEDAOBgNVBAsTB0JpdFhIdWIxEDAOBgNVBAMTB0JpdFhIdWIwWTATBgcq
hkjOPQIBBggqhkjOPQMBBwNCAATgjTYEnavxerFuEKJ8C39QUY12xh/TC2E5V7ni
nmQcOgDDRv5HW4sskTSm/WX2D0BMzwb7XE5ATyoDeM9qcurDozEwLzAOBgNVHQ8B
Af8EBAMCAaYwDwYDVR0lBAgwBgYEVR0lADAMBgNVHRMBAf8EAjAAMAoGCCqGSM49
BAMCA0kAMEYCIQD5Oz1xJvFgzYm/lTzoaO/i0ayPVRgSdBwvK6hEICo5lAIhAMtG
aswjd2wVA4zB5GPEmJ/tvPUnxrlOAU67AQMYR4zf`,
},
},
Authentication: []bitxid.Auth{{PublicKey: []string{"KEY#1"}, Strategy: "1-of-1"}},
},
}
// 初始化存储:
dirTable, _ := ioutil.TempDir("", "did.table")
l := log.NewWithModule("chain-did")
sTable, _ := leveldb.New(dirTable)
// 构建一个 ChainDIDRegistry 实例(ExternalDocDB模式,无需WithChainDocStorage):
mr, _ := bitxid.NewChainDIDRegistry(sTable, l,
bitxid.WithAdmin(adminDID),
bitxid.WithGenesisChainDocInfo(
bitxid.DocInfo{ID: relaychainDID, Addr: relaychainDocAddr, Hash: relaychainDocHash[:]},
),
)
// 初始化 ChainDIDRegistry
_ = mr.SetupGenesis()
// 申请 Chain DID:
mr.Apply(mcaller, chainDID)
// 审批 Chain DID:
mr.AuditApply(chainDID, true)
// 注册 Chain DID:
docAddr := fakeStore(&appchainDoc) // 假设将Doc进行了存储,返回了存储地址
docBytes, _ = appchainDoc.Marshal()
docHash := fakeHash(docBytes) // 假设将Doc进行了哈希,返回了哈希结果
mr.Register(chainDID, docAddr, docHash[:])
// 更新 Chain DID:
appchainDoc.Updated = uint64(1616986227)
docBytes, _ = bitxid.Marshal(appchainDoc)
docAddr = fakeStore(&appchainDoc) // 假设将Doc进行了存储,返回了存储地址
docHash = fakeHash(docBytes) // 假设将Doc进行了哈希,返回了哈希结果
mr.Update(chainDID, docAddr, docHash[:])
// 冻结 Chain DID:
mr.Freeze(chainDID)
// 解冻 Chain DID:
mr.UnFreeze(chainDID)
// 解析 Chain DID:
item, _, _, _ := mr.Resolve(chainDID)
fmt.Println(item)
docGet := fakeGetDoc(item.DocAddr) // 假设去链下获取存储的文档原文
docGetBytes, _ := docGet.Marshal()
docHashGet := fakeHash(docGetBytes)
if !bytes.Equal(docHashGet[:], item.DocHash) {
return // 哈希不匹配,说明链下存储的文档被篡改不可信,解析失败
}
interchain_tx := fakeReceiveInterchainTX()
if !fakeVerify(docGet.Authentication, interchain_tx) {
return // 交易合法性验证失败,说明交易发起者不符合权限要求
}
// 删除 Chain DID:
mr.Delete(chainDID)
fakeDeleteDoc(chainDID) // 假设此处去删除链下存储的文档
// 清除存储
mr.Table.Close()
os.RemoveAll(dirTable)
}
func fakeHash(docBytes []byte) [32]byte {
return sha256.Sum256(docBytes)
}
func fakeStore(d bitxid.Doc) string {
return "/storage/address/to/doc/" + fmt.Sprint(time.Now().Second())
}
func fakeGetDoc(docAddr string) bitxid.ChainDoc {
return bitxid.ChainDoc{
BasicDoc: bitxid.BasicDoc{
ID: "did:bitxhub:appchain001:.",
Type: int(bitxid.ChainDIDType),
Created: 1616985208,
Updated: 1616986227,
PublicKey: []bitxid.PubKey{
{
ID: "KEY#1",
Type: "secp256k1",
PublicKeyPem: `MIICWjCCAf+gAwIBAgIDDhFLMAoGCCqGSM49BAMCMIGaMQswCQYDVQQGEwJDTjER
MA8GA1UECBMIWmhlSmlhbmcxETAPBgNVBAcTCEhhbmdaaG91MR8wDQYDVQQJEwZz
dHJlZXQwDgYDVQQJEwdhZGRyZXNzMQ8wDQYDVQQREwYzMjQwMDAxDzANBgNVBAoT
BkFnZW5jeTEQMA4GA1UECxMHQml0WEh1YjEQMA4GA1UEAxMHQml0WEh1YjAgFw0y
MDA4MTEwNTA3MTNaGA8yMDcwMDczMDA1MDcxM1owgZkxCzAJBgNVBAYTAkNOMREw
DwYDVQQIEwhaaGVKaWFuZzERMA8GA1UEBxMISGFuZ1pob3UxHzANBgNVBAkTBnN0
cmVldDAOBgNVBAkTB2FkZHJlc3MxDzANBgNVBBETBjMyNDAwMDEOMAwGA1UEChMF
Tm9kZTExEDAOBgNVBAsTB0JpdFhIdWIxEDAOBgNVBAMTB0JpdFhIdWIwWTATBgcq
hkjOPQIBBggqhkjOPQMBBwNCAATgjTYEnavxerFuEKJ8C39QUY12xh/TC2E5V7ni
nmQcOgDDRv5HW4sskTSm/WX2D0BMzwb7XE5ATyoDeM9qcurDozEwLzAOBgNVHQ8B
Af8EBAMCAaYwDwYDVR0lBAgwBgYEVR0lADAMBgNVHRMBAf8EAjAAMAoGCCqGSM49
BAMCA0kAMEYCIQD5Oz1xJvFgzYm/lTzoaO/i0ayPVRgSdBwvK6hEICo5lAIhAMtG
aswjd2wVA4zB5GPEmJ/tvPUnxrlOAU67AQMYR4zf`,
},
},
Authentication: []bitxid.Auth{{PublicKey: []string{"KEY#1"}, Strategy: "1-of-1"}},
},
}
}
func fakeReceiveInterchainTX() *pb.Transaction {
return &pb.Transaction{}
}
func fakeVerify(a []bitxid.Auth, tx *pb.Transaction) bool {
// 此处理论上只需要成功匹配一种验证方式就可以返回true
return true
}
func fakeDeleteDoc(did bitxid.DID) error {
// 去链下存储删除对应文档
return nil
}其他示例包括Chain DID的InternalDocDB模式以及Account DID的ExternalDocDB模式和InternalDocDB模式示例见examples。
以Chain DID Registry的实例化为例来进行说明,Account DID Registry的实例化方式类似。
传入实现Storage接口的数据结构、日志即可完成实例化(关于Storage接口的详细信息见此处):
// 省略其他代码,见examples/chain-did/internal/example.go
mr, _ := bitxid.NewChainDIDRegistry(sTable, l,
bitxid.WithChainDocStorage(sDocdb),
bitxid.WithAdmin(adminDID),
bitxid.WithGenesisChainDocContent(&relaychainDoc),
)实例化函数拥有如下几个选项函数:
WithChainDocStorage:使用该选项后Registry的将为InternalDocDB模式,如果不使用该选项则为ExternalDocDB模式,入参也是一个Storage接口的数据结构。WithAdmin:指定管理员账号WithGenesisChainDocContent:用于InternalDocDB模式,指定网络中第一条链的身份信息文档原文内容WithGenesisChainDocInfo:用于ExternalDocDB模式,指定网络中第一条链的身份信息文档信息(包括存储地址等)
此部分是 Chain DID Registry 和 Account DID Registry 都有的功能,以 Chain DID Registry 为例进行说明。
进行初始化不需要传入任何参数:
// 省略其他代码,见examples/chain-did/internal/example.go
_ = mr.SetupGenesis()对链管理来说是GenesisChainDID,对账户管理来说是GenesisAccountDID。
chainDID := mr.GetSelfID()admins := mr.GetAdmins()admin := bitxid.DID("did:bitxhub:relaychain001:0x12345678")
err := mr.AddAdmin(admin)err := mr.RemoveAdmin(admin)err := mr.HasAdmin(admin)以下是Chain DID的特有功能。
申请一个Chain DID的所有权:
// 省略其他代码,见examples/chain-did/internal/example.go
chainDID := bitxid.DID("did:bitxhub:appchain001:.")
mcaller := bitxid.DID("did:bitxhub:relayroot:0x12345678")
err := mr.Apply(mcaller, method)对某个Chain DID的申请进行审批(审批结果为“通过”):
err := mr.AuditApply(chainDID, true)对某个Chain DID的申请进行审批(审批结果为“驳回”):
err := mr.AuditApply(method, false)在审核通过后,可以进行注册,如果是 ExternalDocDB 模式:
docAddr := fakeStore(&appchainDoc) // 假设将Doc进行了存储,返回了存储地址
docBytes, _ = appchainDoc.Marshal()
docHash := fakeHash(docBytes) // 假设将Doc进行了哈希,返回了哈希结果
mr.Register(chainDID, docAddr, docHash[:])此处是 ExternalDocDB 模式,因此需要自己手动将相关信息的文档进行存储,并进行哈希,然后将chainDID, docAddr, docHash作为参数传入Register方法。
如果是 InternalDocDB 模式:
mr.RegisterWithDoc(&appchainDoc)InternalDocDB 模式看上去更加简单,因为链上的逻辑能帮你完成所有事情——各种格式变换以及存储,但是链上的计算和存储是非常昂贵的。
更新一个Chain DID所绑定的信息,如果是 ExternalDocDB 模式:
appchainDoc.Updated = uint64(1616986227)
docBytes, _ = bitxid.Marshal(appchainDoc)
docAddr = fakeStore(&appchainDoc) // 假设将Doc进行了存储,返回了存储地址
docHash = fakeHash(docBytes) // 假设将Doc进行了哈希,返回了哈希结果
mr.Update(chainDID, docAddr, docHash[:])此处是 ExternalDocDB 模式,因此需要自己手动将相关信息的文档进行存储,并进行哈希,然后将chainDID, docAddr, docHash作为参数传入Update方法。
如果是 InternalDocDB 模式:
appchainDoc.Updated = uint64(1616986227)
mr.UpdateWithDoc(&appchainDoc)获得相关Chain DID的信息,如果是 ExternalDocDB 模式:
item, _, _, _ := mr.Resolve(chainDID)
fmt.Println(item)
docGet := fakeGetDoc(item.DocAddr) // 假设去链下获取存储的文档原文
docGetBytes, _ := docGet.Marshal()
docHashGet := fakeHash(docGetBytes)
if !bytes.Equal(docHashGet[:], item.DocHash) {
return // 哈希不匹配,说明链下存储的文档被篡改不可信,解析失败
}
interchain_tx := fakeReceiveInterchainTX()
if !fakeVerify(docGet.Authentication, interchain_tx) {
return // 交易合法性验证失败,说明交易发起者不符合权限要求
}此处是 ExternalDocDB 模式,因此需要自己手动用存储地址去链下存储获取信息文档,然后将文档内容进行哈希,并和原哈希进行比对以验证文档。然后在文档的使用上,bitxid虽然不强迫但建议使用者在验证身份时只需要符合Authentication数组中的一条验证规则即可证明用户确实已经授权交易。
如果是 InternalDocDB 模式:
item, docGet, _, _ := mr.Resolve(chainDID)
fmt.Println(item)
fmt.Println(docGet)
interchain_tx := fakeReceiveInterchainTX()
if !fakeVerify(docGet.Authentication, interchain_tx) {
return // 交易合法性验证失败,说明交易发起者不符合权限要求
}可以从链上直接获取到DID文档,文档的使用方式一样。
删除相关Chain DID的信息,如果是 ExternalDocDB 模式:
mr.Delete(chainDID)
fakeDeleteDoc(chainDID)链下存储的DID文档需要调用者手动去删除。
如果是 InternalDocDB 模式:
mr.Delete(chainDID)以下是Account DID的特有功能。
获取Account DID Registry所在链的身份:
chainDID := r.GetChainDID()
Account DID不需要申请可以直接进行注册,bitxid强烈建议每个地址应当只能注册以自己为address,以自己所在链为chain-name的DID(did:bitxhub:chain-name:address)。如果开发者不得不打破这个规定,可以自己编写Account DID的申请等功能。
ExternalDocDB 模式下的注册:
docAddr := fakeStore(&accountDoc) // 假设将Doc进行了存储,返回了存储地址
docBytes, _ = accountDoc.Marshal()
docHash := fakeHash(docBytes) // 假设将Doc进行了哈希,返回了哈希结果
ar.Register(accountDID, docAddr, docHash[:])此处是 ExternalDocDB 模式,因此需要自己手动将相关信息的文档进行存储,并进行哈希,然后将accountDID, docAddr, docHash作为参数传入Register方法。
InternalDocDB 模式下的注册:
ar.RegisterWithDoc(&accountDoc)InternalDocDB 模式看上去更加简单,因为链上的逻辑能帮你完成所有事情——各种格式变换以及存储,但是链上的计算和存储是非常昂贵的。
更新一个Account DID所绑定的信息,如果是 ExternalDocDB 模式:
accountDoc.Updated = uint64(1616986228)
docAddr = fakeStore(&accountDoc) // 假设将Doc进行了存储,返回了存储地址
docBytes, _ = bitxid.Marshal(accountDoc)
docHash = fakeHash(docBytes) // 假设将Doc进行了哈希,返回了哈希结果
ar.Update(accountDID, docAddr, docHash[:])此处是 ExternalDocDB 模式,因此需要自己手动将相关信息的文档进行存储,并进行哈希,然后将accountDID, docAddr, docHash作为参数传入Update方法。
如果是 InternalDocDB 模式:
accountDoc.Updated = uint64(1616986228)
ar.UpdateWithDoc(&accountDoc)ar.Freeze(accountDID)ar.UnFreeze(accountDID)如果是 ExternalDocDB 模式:
item, _, _, _ := ar.Resolve(accountDID)
fmt.Println(item)
docGet := fakeGetDoc(item.DocAddr) // 假设去链下获取存储的文档原文
docGetBytes, _ := docGet.Marshal()
docHashGet := fakeHash(docGetBytes)
if !bytes.Equal(docHashGet[:], item.DocHash) {
return // 哈希不匹配,说明链下存储的文档被篡改不可信,解析失败
}
interchain_tx := fakeReceiveInterchainTX()
if !fakeVerify(docGet.Authentication, interchain_tx) {
return // 交易合法性验证失败,说明交易发起者不符合权限要求
}此处是 ExternalDocDB 模式,因此需要自己手动用存储地址去链下存储获取信息文档,然后将文档内容进行哈希,并和原哈希进行比对以验证文档。然后在文档的使用上,与ChainDoc类似。
如果是 InternalDocDB 模式:
item, docGet, _, _ := ar.Resolve(accountDID)
fmt.Println(item)
fmt.Println(docGet)
interchain_tx := fakeReceiveInterchainTX()
if !fakeVerify(docGet.Authentication, interchain_tx) {
return // 交易合法性验证失败,说明交易发起者不符合权限要求
}可以从链上直接获取到DID文档,文档的使用方式一样。
删除相关Chain DID的信息,如果是 ExternalDocDB 模式:
ar.Delete(accountDID)
fakeDeleteDoc(accountDID) // 假设此处去删除链下存储的文档链下存储的DID文档需要调用者手动去删除。
如果是 InternalDocDB 模式:
ar.Delete(accountDID)