Fullstop000's blog

没有钱的程序员


  • 首页

  • 归档

  • 标签

A road to Fabric - create channel 梳理 (上)

发表于 2017-10-10 | 分类于 编程

A road to Fabric - create channel 梳理 (上)

代码版本

Fabric : release 5afac39fcdb1d245aab3a94b825ebadb99cdad72

Fabric-go-sdk : master 9fe40b3f41260f5f4f7c8919117c8b07550871fd

1. 生成 crypto - config

todo

2. 生成 channel.tx

channle.tx 实际上是由 github.com/hyperledger/fabric/protos/common#Envelope 通过proto.marshal()后生成的bytes文件,对应configtx.yaml中的ChannelConfig部分:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Profiles:
# .... 省略OrdererGenesis
ChannelConfig:
Consortium: SampleConsortium
Application:
<<: *ApplicationDefaults
Organizations:
- *Org0
- *Org1
- *Org2
- *Org3
Organizations:
- &Org0
Name: Org0MSP
ID: Org0MSP
mspdir: crypto-config/peerOrganizations/org0.yunphant.coin.com/msp
AnchorPeers:
- Host: peer0.org0.yunphant.coin.com
Port: 7051
# 省略 其他orgs
Application: &ApplicationDefaults
Organizations:

创建Envelop

DSL说明

  • 括号外表示实际使用类型,括号内表示grpc使用的字段,没有括号表示为基本类型
  • 带有@表示已被序列化,即类型为bytes; 带有…对应grpc 中的repeated关键字
  • 较复杂的类型使用Go的表达方式

对字段类型有疑问请参考fabric/protos/common/common.proto与fabric/protos/common/configtx.proto

整个Envelop对象由fabric/common/configtx/template.go#MakeChainCreationTransaction函数生成,之后通过ioutil写入channle.tx文件中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
Envelop:
Payload(payload):
Header(header)@:
ChannelHeader(channel_header)@:
# 表明信息类型,参考下面的HeaderType,创建Channel时使用CONFIG_UPDATE
HeaderType: 2
version: 0
# 设置的交易请求时间,在SDK中会重新设置一次
timestamp:
# channel id 由MakeChainCreationTransaction传入参数决定
channel_id:
# 交易id , 使用SignatureHeader中的两个字段通过SHA-256加密得到的Hash值,虽然创建Envelop时,SignatureHeader两个值均为空,但依然会生成tx_id
tx_id:
epoch: 0
# 根据不同的HeaderType可能有不同用途,CONFIG_UPDATE下为空
extension@:
SignatureHeader(signature_header)@:
# 交易创建者,创建Envelop时为空
creator@:
# 随机数用于加密,创建Envelop时为空
nonce@:
# 实际交易的内容, ConfigUpdateEnvelop对应上面的HeaderType
ConfigUpdateEnvelop(data)@:
ConfigUpdate(config_update)@:
channel_id:
ConfigGroup(read_set):
version:
# 可以看到这里出现了ConfigGroup的递归,可以用于多级组织的嵌套
map<string,ConfigGroup>(groups):
"Applicaiton": ConfigGroup{
map<string,ConfigGroup>(groups):
#key对应Profiles.ChannelConfig.Application.Organizations下org的Name字段
"Org0MSP": ConfigGroup{}
}
map<string,ConfigValue>(values):
"Consortium" : ConfigValue{
#对应Profiles.ChannelConfig.Consortium的值
Name: "SampleConsortium"
}
map<string,ConfigPolicy>(policies):
mod_policy;
ConfigGroup(write_set):
version:
map<string,ConfigGroup>(groups):
"Applicaiton": ConfigGroup{
map<string,ConfigGroup>(groups):
#key对应Profiles.ChannelConfig.Application.Organizations下org的Name字段
"Org0MSP": ConfigGroup{}
#此处Policy嵌套较深,参考release版本common/configtx/template.go 230 ~ 237行
map<string,ConfigPolicy>(policies):
#Admins
mod_policy: Admins
#此时wSet未存在verison, wSet的version为1
version: 1
}
map<string,ConfigValue>(values):
"Consortium" : ConfigValue{
#对应Profiles.ChannelConfig.Consortium的值
Name: "SampleConsortium"
}
map<string,ConfigPolicy> policies
mod_policy:
#创建Envelop时为空
ConfigSignature(signatures…):
SignatureHeader:
# 交易创建者,创建Envelop时为空
creator@:
# 随机数用于加密,创建Envelop时为空
nonce@:
signarture:
# 创建Envelop时为空
signature@:
1
2
3
4
5
6
7
8
9
enum HeaderType {
MESSAGE = 0; // Used for messages which are signed but opaque
CONFIG = 1; // Used for messages which express the channel config
CONFIG_UPDATE = 2; // Used for transactions which update the channel config
ENDORSER_TRANSACTION = 3; // Used by the SDK to submit endorser based transactions
ORDERER_TRANSACTION = 4; // Used internally by the orderer for management
DELIVER_SEEK_INFO = 5; // Used as the type for Envelope messages submitted to instruct the Deliver API to seek
CHAINCODE_PACKAGE = 6; // Used for packaging chaincode artifacts for install
}

3 .使用当前User对Envelop.Payload.ConfigUpdateEnvelop签名

以 go sdk为例 pkg/fabric-client/client.go:247 client方法SignChannelConfig

首先创建ConfigUpdateEnvelop.ConfigSignature

sdk
1
2
3
4
5
6
7
8
9
// Identity为&pb_msp.SerializedIdentity{Mspid: u.MspID(),IdBytes: u.EnrollmentCertificate()}的proto.marshal结果, 这里使用了当前User的MspId与ECert
creator, err := c.userContext.Identity()
// ...
nonce, err := fc.GenerateRandomNonce() // 由crypto-suite随机生成
// ...
signatureHeader := &common.SignatureHeader{
Creator: creator,
Nonce: nonce,
}

序列化后与整个ConfigUpdateEnvelop一起使用User private key进行签名返回

1
2
3
4
5
6
7
8
9
10
11
12
13
//&SigningManager{cryptoProvider: cryptoProvider, hashOpts: &bccsp.SHAOpts{}}
signingMgr := c.SigningManager()
//...
// get all the bytes to be signed together, then sign
signingBytes := fcutils.ConcatenateBytes(signatureHeaderBytes, config)
signature, err := signingMgr.Sign(signingBytes, user.PrivateKey())
//...
// build the return object
configSignature := &common.ConfigSignature{
SignatureHeader: signatureHeaderBytes,
Signature: signature,
}
return configSignature, nil

得到签名后构建ChannelCreateRequest 对象,调用CreateChannel方法,

1
2
3
4
5
6
7
8
9
10
11
12
var configSignatures []*common.ConfigSignature
configSignatures = append(configSignatures, configSignature)
request := fab.CreateChannelRequest{
// 注意这里并没有设置Envelop与Txid
Name: channel.Name(),
Orderer: channel.Orderers()[0],
Config: config,
Signatures: configSignatures,
}
// 设置orderer作为当前user,为下一步生成txid做准备
client.SetUserContext(ordererUser)
_, err = client.CreateChannel(request)

4. 重新用Orderer的MSP生成txid,设置Envelop.Payload.Header

在上一步中,client的当前User Context已经设置为Orderer user,c.NewTxnID()会调用当前user的Identity()方法生成序列化的身份证明,之后与一个随机数生成txID

1
2
3
4
5
6
7
8
9
10
11
func (c *Client) CreateChannel(request fab.CreateChannelRequest) (apitxn.TransactionID, error) {
//...
if !haveEnvelope && request.TxnID.ID == "" {
txnID, err := c.NewTxnID()
if err != nil {
return txnID, err
}
request.TxnID = txnID
}
return request.TxnID, c.createOrUpdateChannel(request, haveEnvelope)
}

然后设置Payload header (省略了err catch的代码)可以看到ChannelHeader重新设置了txID为上一步生成的txID,并且通过fc.BuildHeader添加了’创建Envelop’步骤中缺少的SignatureHeader , 在这里所有的signature均适用orderer的私钥

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
configUpdateEnvelope := &common.ConfigUpdateEnvelope{
ConfigUpdate: request.Config,
Signatures: request.Signatures,
}
//重新build header
channelHeader, err := channel.BuildChannelHeader(common.HeaderType_CONFIG_UPDATE, request.Name, request.TxnID.ID, 0, "", time.Now())
creator, err := c.userContext.Identity()
//对header进行签名
header, err := fc.BuildHeader(creator, channelHeader, request.TxnID.Nonce)
configUpdateEnvelopeBytes, err := proto.Marshal(configUpdateEnvelope)
payload := &common.Payload{
Header: header,
Data: configUpdateEnvelopeBytes,
}
payloadBytes, err = proto.Marshal(payload)
signingMgr := c.SigningManager()
signature, err = signingMgr.Sign(payloadBytes, c.UserContext().PrivateKey())

之后在pkg/fabric-client/client.go:341的createOrUpdateChannel中调用Orderer对象的SendBroadcast方法,给Orderer发broadcast请求(关于broadcast / deliver机制 Fabric 官方文档中有详细的说明)

1
2
3
4
5
6
// createOrUpdateChannel 部分代码
// Send request
_, err := request.Orderer.SendBroadcast(&fab.SignedEnvelope{
Signature: signature,
Payload: payloadBytes,
})

在SendBroadcast中使用grpc调用Orderer的Broadcast函数,相关的protobuf为fabric/protos/orderer/ab.proto,接下来进入Orderer内部处理的环节

WebSocket实践(一)

发表于 2017-09-30 | 分类于 编程

简介

WebSocket解决了使用HTTP协议所带来的不能连续接收server端状态变化的问题(如聊天场景),具体区别见下面这张图

img_http_websocket.png

主要区别:

  • HTTP : request - response单向通信,短链接 ; WebSocket : Bi-directional messages双向通信,长链接
  • Websocket在一个链接内能让server主动推送数据给client
    阅读全文 »

怪物猎人xx 全技能效果表

发表于 2017-09-29 | 分类于 游戏

怪物猎人xx 全技能效果表

基础能力值相关

体力

  +15:体力最大値+50

  +10:体力最大値+20

  -10:体力最大値减少10

  -15:体力最大値减少30

阅读全文 »
Fullstop000

Fullstop000

3 日志
2 分类
5 标签
© 2017 Fullstop000
由 Hexo 强力驱动
主题 - NexT.Mist