关于solo模式下修改orderer地址的问题

Fabric 1.1关于solo模式下修改orderer地址的问题

修改orderer的流程

我们知道configtx可以用来修改orderer的地址,官方有标准的文档,可以查看,其主要流程是:

  1. 获取channel的最新pb格式配置块(config block)
  2. 把pb格式的config block转换成json格式
  3. 修改json文件中关于orderer地址的值,手动修改即可
  4. 把json格式的config block文件转换回pb格式
  5. diff前后两个pb格式config block,得到一个config update
  6. 对config update签名
  7. 把签名后的config update提交给orderer来更新地址
  8. orderer验证后会把update块deliver给所有的peer以完成更新

这个过程本身是没有问题的,所有的peers和orderer都能够继续无缝工作,但是问题出在要新加入的peer上。

问题:对新加入的peer

在peer加入channel的时候,需要channel的genesis block作为参数
peer channel join -b {channel-genesis-block}.pb
这个channel-genesis-block一般我们直接取channel的第一个block即可:
peer channel fetch 0 {channel-genesis-block} -c ${CHANNEL} -o ${ORDERERADDR}
问题就在这儿,序号为0的block是channel的genesis block,但是它里面记录的orderer地址是原始的地址,而不是更新后的地址。

从而在peer join的时候从genesis block中拿到的orderer地址是老地址,那么join操作肯定不会成功。

这个地方有一点需要注意:我们为什么不在peer join的命令行中指定orderer地址呢,就像peer channel fetch那样?
答案是不能的,peer channel fetch是把命令直接发给orderer,所以需要在命令行中指定orderer地址,那么我们使用新地址就能工作;而peer join的工作不是把命令发给orderer,而是把命令发给作为server的另一个peer,peer客户端把{channel-genesie-block}这个参数发给了作为server的peer,而并不把orderer地址发给作为server的peer(如果用户强行指定了-o参数,peer join命令直接把它丢弃)。这样作为server的peer收到的参数只有genesis block,然后它从genesis block里面读出orderer地址,显然是个老地址,无法工作。

我们可能会想到两个方案:

  1. 取最新的block作为genesis block,因为它的orderer地址是新的。

答案是不行的:因为peer join的时候要验证收到的block number,最新的config block的block number显然不是0,肯定是过不了的。

(我们是不是可以把这个block number也强行改成0呢,这个我没有试过,不知道行不行哎。)

  1. 从orderer拿到genesis block之后,利用configtx工具把里面的orderer地址改掉再join呢。

这个办法是不是可行呢,相当于说我们欺骗了channel拿一个修改过的genesis block冒充原装block来join channel,经过实际我发现这个方案貌似可行,channel的数据能从orderer同步过来,后续也能工作,唯一留下的缺陷是orderer的block chain和peer的block不一致了,因为peer的genesis block和orderer的genesis block不一致(orderer地址不一致)。

有文化的同学就有疑问了,block chain不一致了,这怎么行,他们不是有hash值来验证所有block的链关系吗,我只能说这个问题说明你很专业,但是看起来config block的部分内容并没有参与到block hash值得计算范围内,至少orderer地址所在的内容没有参与,我们已经明确知道orderer的genesis block和peer的genesis block内容不一致的,但是这两个块最终算出的hash值是一样的,所以整个block chain对fabric来说还是完整的。是不是很滑稽。

那么,这样是不是问题就算解决了呢?当然不是,所以我前面说貌似可行,其实还是不行的。这个方案的可行是有条件的,即整条链从没有修改过配置信息,也就是说除了第一个genesis block,在整条链中其他的全是transactions block,没有其他configure block了。

一旦链中存在另一个configure block,那么在同步这个configure block的时候必然会失败。错误栈如下:

panic: Cannot commit block to the ledger due to ConfigEnvelope LastUpdate did not produce the supplied config result
github.com/hyperledger/fabric/common/configtx.(*ValidatorImpl).Validate
        /opt/gopath/src/github.com/hyperledger/fabric/common/configtx/validator.go:193
github.com/hyperledger/fabric/core/peer.(*chainSupport).Apply
        /opt/gopath/src/github.com/hyperledger/fabric/core/peer/peer.go:93
github.com/hyperledger/fabric/core/committer/txvalidator.validateTx
        /opt/gopath/src/github.com/hyperledger/fabric/core/committer/txvalidator/validator.go:401
github.com/hyperledger/fabric/core/committer/txvalidator.(*txValidator).Validate.func1.1

原因是什么:

orderer: [genesis-block-with-old-addr] -> ... -> [config-block]
peer:    [genesis-block-with-new-addr] -> ... -> validating

在文章一开始的时候,我们提到修改config的时候,提交给orderer的是config update内容,也就是差异部分,所以在config-block里面会记录这个差异部分,然后从差异部分推导出新的完整的config内容,这个新的完整的config也记录在config block里面(所以一个config block包含两块内容:1, config update域包含修改过的项,2,config域包含完整的新的所有项)。如果一个config update没有修改orderer地址,那么config update没有orderer地址这项,从而对orderer来说最终推导出来的完整的新config block使用的是老的orderer地址,而对于peer来说最终推导出来的新的config block使用的是新的orderer地址,(因为如果orderer地址没有在config update域里面,那么他们都会使用之前的config block里面的内容),这导致经过同一个config update之后orderer和peer产出的新的config block内容不一致了,表示peer验证config update失败,从而不能胜利完成同步。

这个问题好像没有正确的解法,我能想到的一个hack的办法就是:把block chain上的所有block捋一遍,把其中所有的config block中的orderer地址强制修改掉,就像老orderer地址从来没有被使用过一样。(前面提过orderer地址的修改,并不影响config block的hash值,所以整个block chain并不会被破坏)

标准解法

前面提到的其实是很不正式的办法,这里提供一个不用hack的办法,但是是有限制的:

  1. 第一步 标准流程修改orderer地址
    把新的orderer地址也加入到channel的orderer地址列表中,这样channel就包含两个orderer地址一个是旧的,一个是就新的,当然当前使用的是旧的。
  2. 第二步 完成block chain的迁移,完成orderer真实地址的切换
    此时channel还是有两个orderer地址一个是旧的,一个是就新的,当然当前使用的是新的了。
  3. 第三步 再次标准流程修改orderer地址
    即把地址中旧的删除,只保留一个新地址即可

这个办法的限制是:

  1. 老的instance必须可用,需要修改config
  2. 新地址必须在老instance可用的时候就确定。
    例如有些场景,需要删除老instance,然后创建新instance,而又必须新instance创建出来之后才能知道新地址(动态分配)的场景就不适用了。

后续

修改orderer地址,对后加入的peer还有隐含问题,试想在一个orderer地址修改的config前后的block如何处理:要么前面的block不工作,要么后面的block不工作,因为orderer地址只有一个呢。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,064评论 5 466
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,606评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,011评论 0 328
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,550评论 1 269
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,465评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,919评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,428评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,075评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,208评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,185评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,191评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,914评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,482评论 3 302
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,585评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,825评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,194评论 2 344
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,703评论 2 339

推荐阅读更多精彩内容