-
Notifications
You must be signed in to change notification settings - Fork 127
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
upgrade module : design doc and the framework codes #46
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
vendor | ||
.idea | ||
.idea | ||
build |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
# Upgrade Module | ||
|
||
本module作为支持区块链软件平滑升级的基础设施,通过upgradeProposal和switch两阶段的投票来在约定高度切换到新版的代码,并对历史版本的链上数据完全兼容。 | ||
|
||
key point: | ||
|
||
* upgradeProposal投票通过后各个节点下载安装新版本软件,并启动软件发送switch投票,表明已经可以切换到新版本 | ||
* switch的投票将在约定高度进行检查,需要95%的Voting Power才视为投票通过 | ||
* switch通过后开启切换流程: | ||
1. check_tx全部返回fail,以拒绝新tx的处理 | ||
2. 处理mempool中留存的tx,直到生成一个empty block | ||
3. 配置新版本的路由开关,并打开check_tx接受新tx | ||
* 发生老版本AppHash冲突,检查自己是否在switch voter list中,否则reset rootMultiStore到上一个commit,并下载新版本开始同步block | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 回滚是应该的,但是之前只考虑了App中store当前版本的回滚,目前讨论下来还需要用新版本软件对自己tendermint node中的last block进行replay,否则还是会有AppHash冲突 |
||
* 新增Module的升级方式(现有Module逻辑修改也通过新Module完成),新老版本的Module共享同一个store,对于查询需要路由到相应版本的Module | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 从iris角度看,查询操作就是直接访问store,然后返回value和proof,具体字段的解析逻辑都是iriscli里面,所以iris本身不需要对查询操作做特殊处理,可能需要在iriscli里面做改动 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OK |
||
* Hardcord的升级方式(bug fix),Upgrade Module提供便利函数来决定指定的代码段在当前区块高度是否执行 | ||
|
||
## Data Struct | ||
|
||
``` | ||
type ModuleLifeTime struct { | ||
Start int64 | ||
End int64 | ||
Handler sdk.Handler | ||
store sdk.KVStoreKey | ||
} | ||
|
||
type Version struct { | ||
Id int // should be equal with corresponding upgradeProposalID | ||
Start int64 | ||
ModuleList []ModuleLifeTime | ||
} | ||
|
||
``` | ||
|
||
## TxMsg | ||
|
||
``` | ||
type MsgSwitch struct { | ||
Title string | ||
ProposalId int | ||
Voter sdk.AccAddress | ||
} | ||
|
||
``` | ||
|
||
## Storage | ||
|
||
| Key | Type | Value | Description | Note| | ||
| --------- | ------ | ------- | -------- | -----------| | ||
| CurrentVersionIDKey | int | CurrentVersionID | c/ | | | ||
| VersionKey | Version | Version | v/%010d/ | v/proposalId | | ||
| VersionListKey | ListOfVersionKey | [][]byte{} | l/ | list of the version_key ordered by proposalId | | ||
| SwitchKey | MsgSwitch | MsgSwitch | s/%010d/%d/ | s/proposalId/switchVoterAddress | |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
package upgrade | ||
|
||
import ( | ||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
) | ||
|
||
const ( | ||
DefaultCodespace sdk.CodespaceType = 1 | ||
|
||
CodeInvalidMsgType sdk.CodeType = 200 | ||
CodeUnknownRequest sdk.CodeType = sdk.CodeUnknownRequest | ||
) | ||
|
||
func codeToDefaultMsg(code sdk.CodeType) string { | ||
switch code { | ||
case CodeInvalidMsgType: | ||
return "Invalid msg type" | ||
default: | ||
return sdk.CodeToDefaultMsg(code) | ||
} | ||
} | ||
|
||
func NewError(codespace sdk.CodespaceType, code sdk.CodeType, msg string) sdk.Error { | ||
msg = msgOrDefaultMsg(msg, code) | ||
return sdk.NewError(codespace, code, msg) | ||
} | ||
|
||
func msgOrDefaultMsg(msg string, code sdk.CodeType) string { | ||
if msg != "" { | ||
return msg | ||
} | ||
return codeToDefaultMsg(code) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package upgrade | ||
|
||
import ( | ||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
"reflect" | ||
"fmt" | ||
) | ||
|
||
func NewHandler(k Keeper) sdk.Handler { | ||
return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { | ||
switch msg := msg.(type) { | ||
case MsgSwitch: | ||
return handlerSwitch(ctx, msg, k) | ||
default: | ||
errMsg := "Unrecognized Upgrade Msg type: " + reflect.TypeOf(msg).Name() | ||
return sdk.ErrUnknownRequest(errMsg).Result() | ||
} | ||
} | ||
} | ||
|
||
func handlerSwitch(ctx sdk.Context, msg sdk.Msg, k Keeper) sdk.Result { | ||
msgSwitch, ok := msg.(MsgSwitch) | ||
if !ok { | ||
return NewError(DefaultCodespace, CodeInvalidMsgType, "Handler should only receive MsgSwitch").Result() | ||
} | ||
|
||
return sdk.Result{ | ||
Code: 0, | ||
Log: fmt.Sprintf("Switch %s by %s", msgSwitch.Title, msgSwitch.Voter.String()), | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package upgrade | ||
|
||
import ( | ||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
"github.com/cosmos/cosmos-sdk/wire" | ||
"github.com/cosmos/cosmos-sdk/x/bank" | ||
) | ||
|
||
type ModuleLifeTime struct { | ||
Start int64 | ||
End int64 | ||
Handler sdk.Handler | ||
store sdk.KVStoreKey | ||
} | ||
|
||
type Version struct { | ||
Id int // should be equal with corresponding upgradeProposalID | ||
Start int64 | ||
ModuleList []ModuleLifeTime | ||
} | ||
|
||
type Keeper struct { | ||
storeKey sdk.StoreKey | ||
cdc *wire.Codec | ||
coinKeeper bank.Keeper | ||
} | ||
|
||
func NewKeeper(cdc *wire.Codec, key sdk.StoreKey, ck bank.Keeper) Keeper { | ||
keeper := Keeper { | ||
storeKey: key, | ||
cdc: cdc, | ||
coinKeeper: ck, | ||
} | ||
return keeper | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package upgrade | ||
|
||
import ( | ||
"fmt" | ||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
) | ||
|
||
var ( | ||
CurrentVersionIDKey = []byte("c/") | ||
VersionKey = "v/%010d/" // v/<proposalId> | ||
SwitchKey = "s/%010d/%d/" // s/<proposalId>/<switchVoterAddress> | ||
) | ||
|
||
func GetCurrentVersionIDKey() []byte { | ||
return CurrentVersionIDKey | ||
} | ||
|
||
func GetVersionKey(proposalID int64) []byte { | ||
return []byte(fmt.Sprintf(VersionKey, proposalID)) | ||
} | ||
|
||
func GetSwitchKey(proposalID int64, switchVoterAddr sdk.AccAddress) []byte { | ||
return []byte(fmt.Sprintf(SwitchKey, proposalID, switchVoterAddr)) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
package upgrade | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 这个switch msg应该是中交易吧,那发起这个交易的应该是轻客户端做的吧,是不是要求一定要 validator owner的签名 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 只接受他是validator的switch |
||
|
||
import ( | ||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
) | ||
|
||
type MsgSwitch struct { | ||
Title string | ||
ProposalID int | ||
Voter sdk.AccAddress | ||
} | ||
|
||
|
||
func (msg MsgSwitch) Type() string { | ||
return "record" | ||
} | ||
|
||
func (msg MsgSwitch) GetSignBytes() []byte { | ||
b, err := msgCdc.MarshalJSON(msg) | ||
if err != nil { | ||
panic(err) | ||
} | ||
return b | ||
} | ||
|
||
func (msg MsgSwitch) ValidateBasic() sdk.Error { | ||
return nil | ||
} | ||
|
||
func (msg MsgSwitch) GetSigners() []sdk.AccAddress { | ||
return []sdk.AccAddress{msg.Voter} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package upgrade | ||
|
||
import ( | ||
"github.com/cosmos/cosmos-sdk/wire" | ||
) | ||
|
||
// Register concrete types on wire codec | ||
func RegisterWire(cdc *wire.Codec) { | ||
cdc.RegisterConcrete(MsgSwitch{}, "iris-hub/MsgSwitch", nil) | ||
} | ||
|
||
var msgCdc = wire.NewCodec() | ||
|
||
func init() { | ||
RegisterWire(msgCdc) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
一个empty block可能有点少,只有一个空块只能说明这个块对应的proposal 节点的memory pool里面是空的,建议等多个empty block
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
社区会公告在第多少高度进行版本升级,提醒届时会终止服务,不要在升级时间段内发交易。所以这里算是一个防御检查,保守一点可以先等两个空块,后续压测发现不足的话再调整。