Orbits网络

2019.07月报(Orbits网络)

目录

  1. 网络层中超级节点的运营以及角色

  2. HyperLedger Fabric的应用以及分析

网络层中超级节点的运营以及角色

2019 Q3

  • 行星钱包(Planet Wallet)上线

  • 开发网络层

在GBT协议的开发路线图中,网络层的开发时间为2019年第三季度,现阶段技术团队正以此为目标进行着相关开发工。 我们通过与现有项目的对比,来分析超级节点的角色以及运行。

在Orbits网络中,超级节点保管着分布式账本的全部内容,超级节点则根据账本中所积累的信用度来选择微小节点,从而实现高效的验证。

1. 提供源文件存储空间

  • 超级节点提供能够存储Dapp源文件的空间,源文件则是以链下的方式存储。

  • 各个超级节点存储的源文件则是由筛选型超级节点来决定。因为奖励的获得与提供的存储容量是成比例的,因此整个过程中不存在选择问题。

2. 为微小节点提供源文件

  • 当微小节点需要源文件时,超级节点须将自身持有的源文件提供给微小节点。

3. 微小节点验证池的生成

  • 超级节点以定期、随机的方式选择节点,用以验证微小节点的交易。

  • 超级节点对发生在微小节点的交易进行排序,并将其传播至选定的验证池。

  • 筛选型超级节点通过检查微小节点是否在线以生成验证池。

HyperLedger Fabric的应用以及分析

在HyperLedger Fabric中,从交易的生成到节点间达成共识,均可按照各个阶段且单独对其进行处理。

首先,在实行(Execute)阶段发起交易后再对交易的结果值进行验证。

其次,交易在实行(Execute)阶段验证完后,会在第二阶段对此前的交易进行排序(Order),排序完后生成相应的区块。

最后,在验证(Validation)过程中,对区块中包含的所有交易所对应的结果值进行验证,完成各种数字验证后,若无异常,则对区块进行更新。

通过这种分离作业的方式,可以减少节点在处理交易以及对交易排序时的负担. 与此同时,由于可以同步并行处理多个任务,系统的性能也随之提高。

HyperLedger Fabric 在系统构建时采用了模块化设计, 参与者可以根据自身需求来选择系统中包含的验证、共识算法、加密等功能,并参与区块链的运营。 这种模块化的设计使得 HyperLedger Fabric 能够灵活的运用于各种商业模式的开发。

1. 背书政策(Endorsement Policy)

背书政策(Endorsement Policy)作用于发起交易的客户端(去中心化应用)与对等者(Peer)之间。 为了将交易打包在区块中,客户端需要获得背书政策中指定对等者(Peer)的许可。 若该交易获得的背书政策不够充分,对等者(Peer)在区块验证过程中则不能将此交易纳入到区块中。

交易在未能获得背书的情况下,其无效标记(invalid tag)的信息会被记录在区块中。 当然,该记录对未来的交易不会产生影响。

我们可以通过下面的例子来看该如何设置背书政策。 首先,我们假设背书集合由以下7个对等者(peer)组成。

背书集合= {peer1, peer2, peer3, peer4, peer5, peer6, peer7}

这种条件下,可以设置如下所示的背书政策(Endorsement Policy)。

  • 获取背书集合中所有对等者(Peer)的数字验证。

  • T获取背书集合中某个对等者(Peer)的数字验证。

  • {peer1 OR peer2} AND {any two of peer5, peer6, peer7}

还可以通过对集合要素赋予加权值来设置背书政策。

背书集合= {peer1 = 15, peer2 = 10, peer3 = 25, peer4 = 20, peer5 = 10, peer6 = 10, peer7 = 10}

  • 加权值合计为50以上时,需从该对等者(Peer)获取数字验证。

  • {peer1 OR peer3} AND {加权值 40 以上}

HyperLedger Fabric 的参与者们可以通过多种方式来设置背书政策。通过这种方式,区块链业务的安全性、可靠性等都得到了加强。

package endorsement
import (
"fmt"
"testing"
"github.com/golang/protobuf/proto"
"github.com/hyperledger/fabric/common/chaincode"
"github.com/hyperledger/fabric/common/policies"
"github.com/hyperledger/fabric/common/policies/inquire"
"github.com/hyperledger/fabric/gossip/api"
"github.com/hyperledger/fabric/gossip/common"
"github.com/hyperledger/fabric/gossip/discovery"
discoveryprotos "github.com/hyperledger/fabric/protos/discovery"
"github.com/hyperledger/fabric/protos/gossip"
"github.com/hyperledger/fabric/protos/msp"
"github.com/hyperledger/fabric/protos/utils"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)
var pkiID2MSPID = map[string]string{
"p0": "Org0MSP",
"p1": "Org1MSP",
"p2": "Org2MSP",
"p3": "Org3MSP",
"p4": "Org4MSP",
"p5": "Org5MSP",
"p6": "Org6MSP",
"p7": "Org7MSP",
"p8": "Org8MSP",
"p9": "Org9MSP",
"p10": "Org10MSP",
"p11": "Org11MSP",
"p12": "Org12MSP",
"p13": "Org13MSP",
"p14": "Org14MSP",
"p15": "Org15MSP",
}
... 중략 ...
func TestPeersAuthorizedByCriteria(t *testing.T) {
cc1 := "cc1"
cc2 := "cc2"
members := peerSet{
newPeer(0).withChaincode(cc1, "1.0"),
newPeer(3).withChaincode(cc1, "1.0"),
newPeer(6).withChaincode(cc1, "1.0"),
newPeer(9).withChaincode(cc1, "1.0"),
newPeer(12).withChaincode(cc1, "1.0"),
}.toMembers()
members2 := append(discovery.Members{}, members...)
members2 = append(members2, peerSet{newPeer(13).withChaincode(cc1, "1.1").withChaincode(cc2, "1.0")}.toMembers()...)
members2 = append(members2, peerSet{newPeer(14).withChaincode(cc1, "1.1")}.toMembers()...)
members2 = append(members2, peerSet{newPeer(15).withChaincode(cc2, "1.0")}.toMembers()...)
alivePeers := peerSet{
newPeer(0),
newPeer(2),
newPeer(4),
newPeer(6),
newPeer(8),
newPeer(10),
newPeer(11),
newPeer(12),
newPeer(13),
newPeer(14),
newPeer(15),
}.toMembers()
identities := identitySet(pkiID2MSPID)
for _, tst := range []struct {
name string
arguments *discoveryprotos.ChaincodeInterest
totalExistingMembers discovery.Members
metadata []*chaincode.Metadata
expected discovery.Members
}{
{
name: "Nil interest",
arguments: nil,
totalExistingMembers: members,
expected: members,
},
{
name: "Empty interest invocation chain",
arguments: &discoveryprotos.ChaincodeInterest{},
totalExistingMembers: members,
expected: members,
},
{
name: "Chaincodes only installed on some peers",
arguments: &discoveryprotos.ChaincodeInterest{
Chaincodes: []*discoveryprotos.ChaincodeCall{
{Name: cc1}, {Name: cc2},
},
},
totalExistingMembers: members2,
metadata: []*chaincode.Metadata{{
Name: "cc1", Version: "1.1",
}, {
Name: "cc2", Version: "1.0",
}},
expected: peerSet{newPeer(13).withChaincode(cc1, "1.1").withChaincode(cc2, "1.0")}.toMembers(),
},
{
name: "Only some peers authorized by collection",
arguments: &discoveryprotos.ChaincodeInterest{
Chaincodes: []*discoveryprotos.ChaincodeCall{
{Name: cc1, CollectionNames: []string{"collection"}},
},
},
totalExistingMembers: members,
metadata: []*chaincode.Metadata{{
Name: cc1, Version: "1.0",
CollectionsConfig: buildCollectionConfig(map[string][]*msp.MSPPrincipal{
"collection": {
peerRole("p0"),
peerRole("p12"),
},
}),
}},
expected: peerSet{
newPeer(0).withChaincode(cc1, "1.0"),
newPeer(12).withChaincode(cc1, "1.0")}.toMembers(),
},
} {
t.Run(tst.name, func(t *testing.T) {
g := &gossipMock{}
pf := &policyFetcherMock{}
mf := &metadataFetcher{}
g.On("Peers").Return(alivePeers)
g.On("IdentityInfo").Return(identities)
g.On("PeersOfChannel").Return(tst.totalExistingMembers).Once()
for _, md := range tst.metadata {
mf.On("Metadata").Return(md).Once()
}
analyzer := NewEndorsementAnalyzer(g, pf, &principalEvaluatorMock{}, mf)
actualMembers, err := analyzer.PeersAuthorizedByCriteria(common.ChainID("mychannel"), tst.arguments)
assert.NoError(t, err)
assert.Equal(t, tst.expected, actualMembers)
})
}
}

根据信赖度的评估参照并使用加权值算法

2. 信道(Channel)

对等网络节点间的通信仅在特定的信道(Channel)进行。所有组织均可通过信道来共享信息。此外,组织间在进行不同的业务时,为平衡彼此间利益关系,部分组织之间也可以通过追加信道来共享信息。各个信道中分别存有各自的分布式账本,以太坊等现有公链中的组织成员均可访问其系统中所在的分布式账本;与以太坊等公链不同,在HyperLedger Fabric中,只有参与指定信道的组织成员才能访问其所属的分布式账本。通过提供指定信道来保证数据的机密性,这是现有公链所无法提供的。

// InitCmdFactory init the ChannelCmdFactory with clients to endorser and orderer according to params
func InitCmdFactory(isEndorserRequired, isPeerDeliverRequired, isOrdererRequired bool) (*ChannelCmdFactory, error) {
if isPeerDeliverRequired && isOrdererRequired {
// this is likely a bug during development caused by adding a new cmd
return nil, errors.New("ERROR - only a single deliver source is currently supported")
}
var err error
cf := &ChannelCmdFactory{}
cf.Signer, err = common.GetDefaultSignerFnc()
if err != nil {
return nil, errors.WithMessage(err, "error getting default signer")
}
cf.BroadcastFactory = func() (common.BroadcastClient, error) {
return common.GetBroadcastClientFnc()
}
// for join and list, we need the endorser as well
if isEndorserRequired {
// creating an EndorserClient with these empty parameters will create a
// connection using the values of "peer.address" and
// "peer.tls.rootcert.file"
cf.EndorserClient, err = common.GetEndorserClientFnc(common.UndefinedParamValue, common.UndefinedParamValue)
if err != nil {
return nil, errors.WithMessage(err, "error getting endorser client for channel")
}
}
// for fetching blocks from a peer
if isPeerDeliverRequired {
cf.DeliverClient, err = common.NewDeliverClientForPeer(channelID, bestEffort)
if err != nil {
return nil, errors.WithMessage(err, "error getting deliver client for channel")
}
}
// for create and fetch, we need the orderer as well
if isOrdererRequired {
if len(strings.Split(common.OrderingEndpoint, ":")) != 2 {
return nil, errors.Errorf("ordering service endpoint %s is not valid or missing", common.OrderingEndpoint)
}
cf.DeliverClient, err = common.NewDeliverClientForOrderer(channelID, bestEffort)
if err != nil {
return nil, err
}
}
logger.Infof("Endorser and orderer connections initialized")
return cf, nil
}

在智能手机中管理UTXO信息时,针对解决数据容量持续增加问题的参考。

3. Gossip

  • 对等者(Peer)在同一信道内不断地生成广播信息。与此同时,位于同一信道内的对等者(Peer)会对其所处的状态进行确认。如果对等者(Peer)在特定时间内未能对广播中的信息做出回应的话会出现何种状况呢? 对等者(Peer)在未能对广播信息作出应答时,则被认为是对等者(Peer)自身发生了问题,并将在网络中将该对等者(Peer)识别为线下状态。

  • 对等者(Peer)通过Gossip协议在同一信道中随机选择对等者(Peer),之后则会将分布式账本传送给被选中的对等者(Peer)。通过Gossip协议接收到分布式账本之后,对等者(Peer)会将其与自己保管的分布式账本做对比,若有最新更新的信息,对等者(Peer)则会将账本进行更新。各个组织内的对等者(Peer)可从 Orderer处更新账本。但是,若组织内的所有对等者(Peer)都从Orderer处邀请并获取更新,Orderer处于过载状态的可能性就会很高。为此,在各个组织中,取而代之的则是通过在对等者(Peer)中选拔 Leader Peer与 Orderer进行通信。

package gossip
import (
"fmt"
"time"
"github.com/hyperledger/fabric/gossip/api"
"github.com/hyperledger/fabric/gossip/comm"
"github.com/hyperledger/fabric/gossip/common"
"github.com/hyperledger/fabric/gossip/discovery"
"github.com/hyperledger/fabric/gossip/filter"
proto "github.com/hyperledger/fabric/protos/gossip"
)
// Gossip is the interface of the gossip component
type Gossip interface {
// SelfMembershipInfo returns the peer's membership information
SelfMembershipInfo() discovery.NetworkMember
// SelfChannelInfo returns the peer's latest StateInfo message of a given channel
SelfChannelInfo(common.ChainID) *proto.SignedGossipMessage
// Send sends a message to remote peers
Send(msg *proto.GossipMessage, peers ...*comm.RemotePeer)
// SendByCriteria sends a given message to all peers that match the given SendCriteria
SendByCriteria(*proto.SignedGossipMessage, SendCriteria) error
// GetPeers returns the NetworkMembers considered alive
Peers() []discovery.NetworkMember
// PeersOfChannel returns the NetworkMembers considered alive
// and also subscribed to the channel given
PeersOfChannel(common.ChainID) []discovery.NetworkMember
// UpdateMetadata updates the self metadata of the discovery layer
// the peer publishes to other peers
UpdateMetadata(metadata []byte)
// UpdateLedgerHeight updates the ledger height the peer
// publishes to other peers in the channel
UpdateLedgerHeight(height uint64, chainID common.ChainID)
// UpdateChaincodes updates the chaincodes the peer publishes
// to other peers in the channel
UpdateChaincodes(chaincode []*proto.Chaincode, chainID common.ChainID)
// Gossip sends a message to other peers to the network
Gossip(msg *proto.GossipMessage)
// PeerFilter receives a SubChannelSelectionCriteria and returns a RoutingFilter that selects
// only peer identities that match the given criteria, and that they published their channel participation
PeerFilter(channel common.ChainID, messagePredicate api.SubChannelSelectionCriteria) (filter.RoutingFilter, error)
// Accept returns a dedicated read-only channel for messages sent by other nodes that match a certain predicate.
// If passThrough is false, the messages are processed by the gossip layer beforehand.
// If passThrough is true, the gossip layer doesn't intervene and the messages
// can be used to send a reply back to the sender
Accept(acceptor common.MessageAcceptor, passThrough bool) (<-chan *proto.GossipMessage, <-chan proto.ReceivedMessage)
// JoinChan makes the Gossip instance join a channel
JoinChan(joinMsg api.JoinChannelMessage, chainID common.ChainID)
// LeaveChan makes the Gossip instance leave a channel.
// It still disseminates stateInfo message, but doesn't participate
// in block pulling anymore, and can't return anymore a list of peers
// in the channel.
LeaveChan(chainID common.ChainID)
// SuspectPeers makes the gossip instance validate identities of suspected peers, and close
// any connections to peers with identities that are found invalid
SuspectPeers(s api.PeerSuspector)
// IdentityInfo returns information known peer identities
IdentityInfo() api.PeerIdentitySet
// Stop stops the gossip component
Stop()
}
... 생략 ...

网络层中通信协议的使用与参考

Reference

  1. HyperLedger Fabric 区块链研习者 / ETRI区块链技术研究中心 Yoon Daegeun/J Pub