各种Store - Agzs/geth-pbft-study GitHub Wiki

xxxStore

pbftCore的成员变量xxxStore:blockStore、certStore、viewChangeStore、newViewStore、checkpointStore。这些store主要用于recvXXX()函数保存接收到的消息。

blockStore

define

blockStore map[string]*types.Block // track request batches

blockStore为字典类型,key是block的hash值,为string类型,一般由string(preprep.BlockHash)hash(preprep.GetBlockMsg())获得key值;valueblock类型,采用ethereum中已定义的block,如下:

// Block represents an entire block in the Ethereum blockchain.
type Block struct {
	header       *Header
	uncles       []*Header
	transactions Transactions

	// caches
	hash atomic.Value
	size atomic.Value

	// Td is used by package core to store the total difficulty of the chain up to and including the block.
	td *big.Int

	// These fields are used by package eth to track inter-peer block relay.
	ReceivedAt   time.Time
	ReceivedFrom interface{}
}

Usage

blockfabric中的requestBatch替换,并且用blockStore替换reqBatchStore

reqBatchStore主要用于request请求的打包,现在简化为Block,不需要做任何处理,走一遍共识过程就ok了。

certStore

define

certStore map[msgID]*msgCert // track quorum certificates for requests

certStore为字典类型,keymsgID{v,n}一般通过{view,SequenceNumber}赋值;valuemsgCertmsgCert用于三阶段协议(prePrepare、prepare、commit)消息数目的统计

type msgID struct { // our index through certStore
	v uint64
	n uint64
}
type msgCert struct {
	digest      string            // 保存block的hash的string形式
	prePrepare  *types.PrePrepare // 保存prePrepare消息,注意为指针类型,可在其他函数中修改prepare
	sentPrepare bool              // 标记是否已发送prepare消息
	prepare     []*types.Prepare  // 保存来自各个VP的Prepare消息,用于后期统计prepare消息的数目
	sentCommit  bool              // 标记是否已发送commit消息
	commit      []*types.Commit   // 保存来自各个VP的commit消息,用于后期统计commit消息的数目
}

prePrepare、prepare、commit结构如下:

type PrePrepare struct {
	View           uint64 `protobuf:"varint,1,opt,name=view" json:"view,omitempty"`
	SequenceNumber uint64 `protobuf:"varint,2,opt,name=sequence_number,json=sequenceNumber" json:"sequence_number,omitempty"`
	BlockHash      []byte `protobuf:"bytes,3,opt,name=block_hash,json=blockHash,proto3" json:"block_hash,omitempty"`
	Block          *Block `protobuf:"bytes,4,opt,name=block_msg,json=blockMsg" json:"block_msg,omitempty"`
	ReplicaId      uint64 `protobuf:"varint,5,opt,name=replica_id,json=replicaId" json:"replica_id,omitempty"`
}

type Prepare struct {
	View           uint64 `protobuf:"varint,1,opt,name=view" json:"view,omitempty"`
	SequenceNumber uint64 `protobuf:"varint,2,opt,name=sequence_number,json=sequenceNumber" json:"sequence_number,omitempty"`
	BlockHash      []byte `protobuf:"bytes,3,opt,name=block_hash,json=blockHash,proto3" json:"block_hash,omitempty"`
	ReplicaId      uint64 `protobuf:"varint,4,opt,name=replica_id,json=replicaId" json:"replica_id,omitempty"`
}

type Commit struct {
	View           uint64 `protobuf:"varint,1,opt,name=view" json:"view,omitempty"`
	SequenceNumber uint64 `protobuf:"varint,2,opt,name=sequence_number,json=sequenceNumber" json:"sequence_number,omitempty"`
	BlockHash      []byte `protobuf:"bytes,3,opt,name=block_hash,json=blockHash,proto3" json:"block_hash,omitempty"`
	ReplicaId      uint64 `protobuf:"varint,4,opt,name=replica_id,json=replicaId" json:"replica_id,omitempty"`
}

值得注意的是,同一个区块的prePrepare、prepare、commit中相同变量保存的数值都是相同的,比如SequenceNumber在三个结构体中保存的都是同一个数值。

Usage

根据{view,seqNo}组成的msgID获取cert,注意到只在func (instance *pbftCore) getCert(v uint64, n uint64) (cert *msgCert)中添加新的cert.其他处的调用只是获取cert,然后使用cert的成员变量判断条件,进行其他操作。

viewChangeStore

define

viewChangeStore map[vcidx]*types.ViewChange // track view-change messages

type vcidx struct {
	v  uint64
	id uint64
}
type ViewChange struct {
	View      uint64           `protobuf:"varint,1,opt,name=view" json:"view,omitempty"`
	H         uint64           `protobuf:"varint,2,opt,name=h" json:"h,omitempty"`
	Cset      []*ViewChange_C  `protobuf:"bytes,3,rep,name=cset" json:"cset,omitempty"`
	Pset      []*ViewChange_PQ `protobuf:"bytes,4,rep,name=pset" json:"pset,omitempty"`
	Qset      []*ViewChange_PQ `protobuf:"bytes,5,rep,name=qset" json:"qset,omitempty"`
	ReplicaId uint64           `protobuf:"varint,6,opt,name=replica_id,json=replicaId" json:"replica_id,omitempty"`
	Signature []byte           `protobuf:"bytes,7,opt,name=signature,proto3" json:"signature,omitempty"`
	Signer    common.Address   `protobuf:"bytes,8,opt,name=signer,proto3" json:"signature,omitempty"` //=> add Signer used for verifying signature --Agzs
}

Usage

viewchangeStore用于保存viewchange的信息,且仅在recvViewChange(vc *ViewChange)中被赋值,语句为instance.viewChangeStore[vcidx{vc.View, vc.ReplicaId}] = vc,其它的调用都只是获取其中的viewChange信息

newViewStore

define

newViewStore map[uint64]*types.NewView // track last new-view we received or sent

type NewView struct {
	View      uint64            `protobuf:"varint,1,opt,name=view" json:"view,omitempty"`
	Vset      []*ViewChange     `protobuf:"bytes,2,rep,name=vset" json:"vset,omitempty"`
	Xset      map[uint64]string `protobuf:"bytes,3,rep,name=xset" json:"xset,omitempty" protobuf_key:"varint,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
	ReplicaId uint64            `protobuf:"varint,4,opt,name=replica_id,json=replicaId" json:"replica_id,omitempty"`
}

Usage

newViewStore用于保存NewView,当同一个viewviewchange到达一定的的数量(instance.N - instance.f)后,就会产生viewChangeQuorumEvent,在收到 viewChangeQuorumEvent事件后, 会产生NewViewsend操作

viewChangeQuorumEvent is returned to the event loop when a new ViewChange message is received which is part of a quorum cert

newViewStore的赋值操作只在下面两个函数中进行:

func (instance *pbftCore) sendNewView() events.Event {
        ...
	nv := &NewView{
		View:      instance.view,
		Vset:      vset,
		Xset:      msgList,
		ReplicaId: instance.id,
	}
	...
	instance.newViewStore[instance.view] = nv
	return instance.processNewView()
}

func (instance *pbftCore) recvNewView(nv *NewView) events.Event {
	logger.Infof("Replica %d received new-view %d",instance.id, nv.View)
	...
	instance.newViewStore[nv.View] = nv
	return instance.processNewView()
}

checkpointStore

define

checkpointStore map[Checkpoint]bool // track checkpoints as set

type Checkpoint struct {
	SequenceNumber uint64 `protobuf:"varint,1,opt,name=sequence_number,json=sequenceNumber" json:"sequence_number,omitempty"`
	ReplicaId      uint64 `protobuf:"varint,2,opt,name=replica_id,json=replicaId" json:"replica_id,omitempty"`
	Id             string `protobuf:"bytes,3,opt,name=id" json:"id,omitempty"`   //=>checkpoint's name
}

Usage

checkpointStore用于保存checkpoint, checkpoint主要用于垃圾回收和viewchange中:

我们一连执行了K条请求,在第K条请求执行完时,向全网发起广播,告诉大家它已经将这K条执行完毕,要是大家反馈说这K条我们也执行完毕了,那就可以删除这K条的信息了,接下来再执行K条,完成后再发起一次广播,即每隔K条发起一次全网共识,这个概念叫checkpoint,每隔K条去征求一下大家的意见,要是获得了大多数的认同(a quorum certificate with 2 f + 1 CHECKPOINT messages (including its own)),就形成了一个 stable checkpoint(记录在第K条的编号)

We refer to the states produced by the execution of these requests as checkpoints and we say that a checkpoint with a proof is a stable checkpoint.

checkpointStore的赋值操作仅在recvCheckpoint()函数中:

func (instance *pbftCore) recvCheckpoint(chkpt *Checkpoint) events.Event {
	logger.Debugf("Replica %d received checkpoint from replica %d, seqNo %d, digest %s", instance.id, chkpt.ReplicaId, chkpt.SequenceNumber, chkpt.Id)

	...
	instance.checkpointStore[*chkpt] = true

	...
	logger.Debugf("Replica %d found checkpoint quorum for seqNo %d, digest %s", instance.id, chkpt.SequenceNumber, chkpt.Id)

	instance.moveWatermarks(chkpt.SequenceNumber)

	return instance.processNewView()
}