Section2.3.4 blockchain

ReadOnlyLedger

ReadOnlyLedger is used for interrogating the blockchain.

type ReadOnlyLedger interface {
    GetBlock(id uint64) (block *pb.Block, err error)
    GetBlockchainSize() uint64
    GetBlockchainInfo() *pb.BlockchainInfo
    GetBlockchainInfoBlob() []byte
    GetBlockHeadMetadata() ([]byte, error)
}

在fabric中, 储存交易的最高层的数据结构称作Ledger, blockchain是定义在Ledger之内的, 同时也是Ledger私有的, 不暴露给外部使用. 因此, 对于blockchain的操作, 都是经过Ledger.

Usage

和前面介绍的接口一样, ReadOnlyLedger也只作为Stack的一部分出现.

Implement

Helper中, 每次对ReadOnlyLedger内几个函数的实现, 都是先通过调用func ledger.GetLedger()获得ledger, 然后执行对应的方法.

// GetBlock returns a block from the chain
func (h *Helper) GetBlock(blockNumber uint64) (block *pb.Block, err error) {
    ledger, err := ledger.GetLedger()
    if err != nil {
        return nil, fmt.Errorf("Failed to get the ledger :%v", err)
    }
    return ledger.GetBlockByNumber(blockNumber)
}

查看func GetLedger()其实可以发现, 它也并没有每次都生成一个Ledger, 而是只生成一次, 以后的都会返回同一个.

// GetLedger - gives a reference to a 'singleton' ledger
func GetLedger() (*Ledger, error) {
    once.Do(func() {
        ledger, ledgerError = GetNewLedger()
    })
    return ledger, ledgerError
}

Ledger内部自己是通过调用blockchain的方法来实现的.

func (ledger *Ledger) GetBlockByNumber(blockNumber uint64) (*protos.Block, error) {
    if blockNumber >= ledger.GetBlockchainSize() {
        return nil, ErrOutOfBounds
    }
    return ledger.blockchain.getBlock(blockNumber)
}

blockchain内则通过操作数据库来实现.

Summary

在fabric中, blockchain被封装在了Ledger内, ReadOnlyLedger定义了对Blockchain的读操作, Helper使用Ledger对其进行了实现, 而Ledger内部则是调用了blockchain的对应方法, blockchain则是通过使用db进行了实现.

LegacyExecutor

LegacyExecutor is used to invoke transactions, potentially modifying the backing ledger

type LegacyExecutor interface {
    BeginTxBatch(id interface{}) error
    ExecTxs(id interface{}, txs []*pb.Transaction) ([]byte, error)
    CommitTxBatch(id interface{}, metadata []byte) (*pb.Block, error)
    RollbackTxBatch(id interface{}) error
    PreviewCommitTxBatch(id interface{}, metadata []byte) ([]byte, error)
}

ReadOnlyLedger类似, 只不过LegacyExecutor内定义的是写操作.

Usage

  • 作为Stack的一部分. 此处和ReadOnlyLedger类似.

  • 作为consensus/executor.PartialStack接口定义的一部分.

    // PartialStack contains the ledger features required by the executor.Coordinator
    type PartialStack interface {
      consensus.LegacyExecutor
      GetBlockchainInfo() *pb.BlockchainInfo
    }

    PartialStack只在executor内部被作为type coordinatorImpl struct的成员变量来使用. executor是作为Helper的一部分来使用, 用来处理实际Tx的执行动作. 前面提到obcBatch使用了event.Manager模块进行消息接收处理, 其实executor也注册了一个event.Manager用来接收执行后的消息. 就是说, 当obcEvent接收到来自pbft的消息后(比如executedEvent), obcEvent会执行相应动作(比如Commit), 这个动作是在Helper里定义的, 但是是通过executor来实现的, executor会把对应时间发给自己的EventManager, EventManager再将消息传回executor, executor收到消息后进行执行. 执行动作就会用到我们刚才提到的接口.

Implement

虽然这里也有两类使用, 但是Usage#2中, PartialStack接口也是用Helper来实现的, 所以也就只有在Helper处的一处实现.

Helper中的实现, 一部分也是直接通过与Ledger交互来实现的. 如:

func (h *Helper) BeginTxBatch(id interface{}) error {
    ledger, err := ledger.GetLedger()
    if err != nil {
        return fmt.Errorf("Failed to get the ledger: %v", err)
    }
    if err := ledger.BeginTxBatch(id); err != nil {
        return fmt.Errorf("Failed to begin transaction with the ledger: %v", err)
    }
    ...
}

而对于func ExecTxs(), 则是通过chaincode.

func (h *Helper) ExecTxs(id interface{}, txs []*pb.Transaction) ([]byte, error) {
    ...
    succeededTxs, res, ccevents, txerrs, err := chaincode.ExecuteTransactions(context.Background(), chaincode.DefaultChain, txs)
    ...
}

Summary

LegacyExecutor用来对blockchain进行写操作, 实际实现只有一处, 在Helper中, 另一处在executor里虽作为一部分定义了一个新的接口, 但该接口仍是通过Helper来初始化的. 在Helper中, 除func ExecTxs()是和chaincode交互实现的, 其他仍是和Ledger交互. executor的存在, 主要是为了方便收集来自obcBatch关于对blockchain写操作的消息, 集中调用Helper进行执行.

Executor

Executor is intended to eventually supplant the old Executor interface. The problem with invoking the calls directly above, is that they must be coordinated with state transfer, to eliminate possible races and ledger corruption.

type Executor interface {
    Start()                                                                     // Bring up the resources needed to use this interface
    Halt()                                                                      // Tear down the resources needed to use this interface
    Execute(tag interface{}, txs []*pb.Transaction)                             // Executes a set of transactions, this may be called in succession
    Commit(tag interface{}, metadata []byte)                                    // Commits whatever transactions have been executed
    Rollback(tag interface{})                                                   // Rolls back whatever transactions have been executed
    UpdateState(tag interface{}, target *pb.BlockchainInfo, peers []*pb.PeerID) // Attempts to synchronize state to a particular target, implicitly calls rollback if needed
}

Executor是用来执行tx的, 其中也会包含执行后的动作(调用func Commited()等).

Usage

Executor也被定义为Stack的一部分, 在Helper内进行了实现, 实际上是Helperexecutor来实现的, Helper只是进行了封装, Helper这些函数, 在func obcBatch.ProcessEvent()中被调用(并非全部使用).

Implement

executor对这些方法只是简单地将数据封装成一个新的时间, 交给event.Manager, 然后在func ProcessEvent()中集中处理.

func (co *coordinatorImpl) Commit(tag interface{}, metadata []byte) {
    co.manager.Queue() <- commitEvent{tag, metadata}
}
func (co *coordinatorImpl) ProcessEvent(event events.Event) events.Event {
    switch et := event.(type) {
    case executeEvent:
        ...
        co.rawExecutor.ExecTxs(co, et.txs)
        co.consumer.Executed(et.tag)
    case commitEvent:
        ...
        _, err := co.rawExecutor.CommitTxBatch(co, et.metadata)
        ...
        info := co.rawExecutor.GetBlockchainInfo()
        ...
        co.consumer.Committed(et.tag, info)
    case rollbackEvent:
        ...
    case stateUpdateEvent:
        ...
    default:
        logger.Errorf("Unknown event type %s", et)
    }

    return nil
}

注意到rawExecutor, 它其实就是实现了LegacyExecutor的接口(实际上是PartialStack), 后面又调用了consumer, 即Event中介绍的ExecutionConsumer, 从这里就可以看出, Executor其实就是把两个接口内的方法又进行了封装.

Summary

Executor作为Stack的一部分以Helper实现, 本质上是由executor.coordinatorImpl来实现的. 在内容上, 就是将LegacyExecutorExecutionConsumer接口封装到一块.

LedgerManager

LedgerManager is used to manipulate the state of the ledger

type LedgerManager interface {
    InvalidateState() // Invalidate informs the ledger that it is out of date and should reject queries
    ValidateState()   // Validate informs the ledger that it is back up to date and should resume replying to queries
}

LedgerManager内只定义了两个方法, 而且还都没有参数, 就是设置当前的Ledger是否是最新的.

Usage

只作为Stack的一部分使用. 两个函数被pbft进一步封装成了innerStack的函数, 会在需要临时禁用Ledger的时候(func stateTransfer()等)处或检测到状态过期的时候调用func InvalidateState(), 会在收到stateUpdatedEvent消息后调用func ValidateState()重新启用Ledger.

Implement

实现很简单, 在Helper中保存了一个bool变量, 分别置为false, true.

Summary

LedgerManager也是Stack的一部分, 用于设置Ledger的状态是否最新/合法, 会在状态转换前或检测到失效后置false, 收到stateUpdatedEvent后重新置true.

Last updated

Was this helpful?