hyperledger / fabric-admin-sdk

Hyperledger Fabric admin SDK
Apache License 2.0
31 stars 19 forks source link

to support GetConfigBlockFromOrdererByNumber #124

Open 1gezhanghao opened 1 year ago

1gezhanghao commented 1 year ago

For an exist channel , when a new org need to be added to channel: the channel's configBlock is updated first, then the org's peers join the channel

code may like as follows

//code update the configblock
...
...

//code to get the latest configblock
block, err = channel.GetConfigBlockFromOrderer(context.Background(), orderer0.Conn, orderer0.Signer, channelID, orderer0.KeyPair)                                                                                                         
if err != nil {                                                                                                                                                                                                                           
        logger.Error(err)                                                                                                                                                                                                                 
        return err                                                                                                                                                                                                                        
}  
//code to make peer join the channel
err := channel.JoinChannel(block, peerCli.Signer, peer.NewEndorserClient(peerCli.Conn))                                                                                                                                           
if err != nil {                                                                                                                                                                                                                   
        logger.Error(err)                                                                                                                                                                                                                 
        return err                                                                                                                                                                                              
}                                                                                                                                                                                                                                 

JoinChannel(...) will give an error: unsuccessful response received with status 500 (INTERNAL_SERVER_ERROR): cannot create ledger from genesis block: expected block number=0, received block number=1

So when a peer join the channl it will always need the number 0 ConfigBlock, is it correct? but channel.GetConfigBlockFromOrderer(...) always return the latest ConfigBlock so we need a func like channel.GetConfigBlockFromOrdererByNumber(0) or channel.GetFirstConfigBlockFromOrderer() to get the first ConfigBlock to support peer join

bestbeforetoday commented 1 year ago

I think you are mixing two separate concerns. The GetConfigBlockFromOrderer function is needed to get the current config block in order to update the channel configuration. This function is helpful because you don't necessarily know the latest configuration block number, and this function both finds the latest configuration block number and then obtains the block for you.

The genesis block is just block zero. You don't need any special admin function to get a specific block by its number. To get block zero, you can either:

  1. Use block eventing to get block events from block zero and stop as soon as you receive that initial block; or
  2. Evaluate the GetBlockByNumber transaction function on the qscc system chaincode.

Perhaps you could argue that it is convenient for the admin API to provide a GetGenesisBlock function but I am not convinced that it is worth increasing the size of the admin API for something that is already easily achieved using the existing client application APIs. The exception to this is for the situation where you need to join peers to channels that contain no peers. The client APIs talk to peers, whereas you would need to obtain to genesis block from an orderer, which the admin API could do with a GetGenesisBlock function. If you are in this situation then perhaps you are the creator of the network anyway, in which case you should already have the genesis block you used to create that network with no peers.

1gezhanghao commented 1 year ago

@bestbeforetoday

I'll explain step by step more clearly,

1 orderer cluster create a channel, there is no org info on the configblock now.

2 org A join the channel:

3 org B join the channel:

For org B, there is no way to get the GenesisBlock from it's peer before it joined in except use an api from orderer. i don't think save the GenesisBlock on local disk by user is a goog idea once the channel be created

and JoinChannel on the old fabric-sdk-go is designed without blockinfo, it is more simple.

func (rc *Client) JoinChannel(channelID string, options ...RequestOption) error {

so, maybe ChannelJoin API can be designed more simpler without blockinfo or give a GetGenesisBlock can solve the problem maybe GetConfigBlockFromOrderer give two block is a good way the LatestBlock & the GenesisBlock.

1gezhanghao commented 1 year ago

I extended a funtion GetGenesisBlockFromOrderer myself,this issue is closed for me.

func GetGenesisBlockFromOrderer(ctx context.Context, connection grpc.ClientConnInterface, id identity.SigningIdentity, channelID string, certificate tls.Certificate) (*cb.Block, error) {                                                                 
        abClient := ab.NewAtomicBroadcastClient(connection)                                                                                                                                                                                                
        deliverClient, err := abClient.Deliver(ctx)                                                                                                                                                                                                        
        if err != nil {                                                                                                                                                                                                                                    
                return nil, err                                                                                                                                                                                                                            
        }                                                                                                                                                                                                                                                  
        return getSpecifiedBlock(deliverClient, channelID, certificate, id, true, 0)                                                                                                                                                                       
}    
bestbeforetoday commented 1 year ago

I agree, if the channel join API can be simplified so the caller does not need to supply genesis and/or config blocks themselves, that might be the neatest solution.