Skip to content

Commit dbd58f3

Browse files
tendermintp2p,raftp2p: implement block rollback
- wasmx-as-contracts commit f9cac107f76ed85ca085e18d7328d65ce825999d
1 parent 2072b5b commit dbd58f3

12 files changed

Lines changed: 219 additions & 23 deletions

File tree

tests/testdata/tinygo/wasmx-blocks/lib/calldata.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ type CallData struct {
77
SetConsensusParams *CallDataSetConsensusParams `json:"setConsensusParams,omitempty"`
88
SetIndexedTransactionByHash *CallDataSetIndexedTransactionByHash `json:"setIndexedTransactionByHash,omitempty"`
99
BootstrapAfterStateSync *CallDataBootstrap `json:"bootstrapAfterStateSync,omitempty"`
10+
Rollback *CalldataRollback `json:"rollback,omitempty"`
1011

1112
GetIndexedData *CallDataGetIndexedData `json:"getIndexedData,omitempty"`
1213
GetLastBlockIndex *CallDataGetLastBlockIndex `json:"getLastBlockIndex,omitempty"`
@@ -84,3 +85,10 @@ type CallDataBootstrap struct {
8485
LastHeightChanged int64 `json:"last_height_changed"`
8586
Params []byte `json:"params"`
8687
}
88+
89+
type CalldataRollback struct {
90+
Height int64 `json:"height"`
91+
Hash []byte `json:"hash"`
92+
TxHashes [][]byte `json:"txhashes"`
93+
IndexedTopics []IndexedTopic `json:"indexed_topics"`
94+
}

tests/testdata/tinygo/wasmx-consensus-utils/lib/utils.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ type IndexedTopic struct {
201201
Values []string `json:"values"`
202202
}
203203

204-
func ExtractIndexedTopics(finalizeResp consensus.ResponseFinalizeBlock, txhashes [][]byte) []IndexedTopic {
204+
func ExtractIndexedTopics(txResults []consensus.ExecTxResult, txhashes [][]byte) []IndexedTopic {
205205
topicMap := map[string][]string{}
206206
push := func(topic string, txhash []byte) {
207207
if len(topic) > MaxKeyLength {
@@ -211,8 +211,8 @@ func ExtractIndexedTopics(finalizeResp consensus.ResponseFinalizeBlock, txhashes
211211
arr = append(arr, base64.StdEncoding.EncodeToString(txhash))
212212
topicMap[topic] = arr
213213
}
214-
for i := range finalizeResp.TxResults {
215-
res := finalizeResp.TxResults[i]
214+
for i := range txResults {
215+
res := txResults[i]
216216
for _, ev := range res.Events {
217217
for _, attr := range ev.Attributes {
218218
if attr.Index {

tests/testdata/tinygo/wasmx-raft-lib/lib/action_utils.go

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -424,8 +424,8 @@ func updateConsensusParams(height int64, updates *typestnd.ConsensusParams) erro
424424
}
425425

426426
// Expose select consensus-utils helpers
427-
func extractIndexedTopics(resp typestnd.ResponseFinalizeBlock, txhashes [][]byte) []blocks.IndexedTopic {
428-
topics := consutils.ExtractIndexedTopics(resp, txhashes)
427+
func extractIndexedTopics(txResults []typestnd.ExecTxResult, txhashes [][]byte) []blocks.IndexedTopic {
428+
topics := consutils.ExtractIndexedTopics(txResults, txhashes)
429429
out := make([]blocks.IndexedTopic, len(topics))
430430
for i := range topics {
431431
out[i] = blocks.IndexedTopic{Topic: topics[i].Topic, Values: topics[i].Values}
@@ -1116,3 +1116,30 @@ func WeAreNotAloneInternal(nodes []p2p.NodeInfo, state CurrentState) bool {
11161116
}
11171117
return state.WeAreNotAlone
11181118
}
1119+
1120+
func RollbackBlockData(height int64, hash []byte, txhashes [][]byte, indexedTopics []blocks.IndexedTopic) error {
1121+
calldata := blocks.CalldataRollback{
1122+
Height: height,
1123+
Hash: hash,
1124+
TxHashes: txhashes,
1125+
IndexedTopics: indexedTopics,
1126+
}
1127+
1128+
payload := map[string]any{
1129+
"rollback": calldata,
1130+
}
1131+
calldatastr, err := json.Marshal(payload)
1132+
if err != nil {
1133+
return fmt.Errorf("failed to marshal rollback data: %s", err.Error())
1134+
}
1135+
1136+
// Call storage
1137+
resp, err := callStorage(string(calldatastr), false)
1138+
if err != nil {
1139+
return fmt.Errorf("could not rollback finalized block: %s: %s", resp.Data, err.Error())
1140+
}
1141+
if resp.Success > 0 {
1142+
return fmt.Errorf("could not rollback finalized block: %s", resp.Data)
1143+
}
1144+
return nil
1145+
}

tests/testdata/tinygo/wasmx-raft-lib/lib/actions.go

Lines changed: 128 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1855,7 +1855,7 @@ func StartBlockFinalizationInternal(entryobj *LogEntryAggregate, retry bool) (bo
18551855
if err != nil {
18561856
return false, err
18571857
}
1858-
indexedTopics := extractIndexedTopics(*finalizeResp, txHashBytes)
1858+
indexedTopics := extractIndexedTopics(finalizeResp.TxResults, txHashBytes)
18591859
if err := setFinalizedBlock(string(blockData), base64.StdEncoding.EncodeToString(processReq.Hash), txHashBytes, indexedTopics); err != nil {
18601860
return false, err
18611861
}
@@ -2256,3 +2256,130 @@ func VerifyCommitLight(params []fsm.ActionParam, event fsm.EventObject) error {
22562256
wasmx.SetFinishData(respbz)
22572257
return nil
22582258
}
2259+
2260+
// Leader usually commits one block in advance
2261+
// so if this node is a follower, it should only remove the block in-waiting to be committed
2262+
// TODO fixme; now we need to go back 2 blocks with the Leader & Followers, otherwise
2263+
// the AppHash has a mismatch
2264+
func Rollback(params []fsm.ActionParam, event fsm.EventObject) error {
2265+
// Extract commit parameter
2266+
height := int64(0)
2267+
for _, p := range params {
2268+
if p.Key == "height" {
2269+
height = parseI64(p.Value, height)
2270+
break
2271+
}
2272+
}
2273+
if height == 0 {
2274+
for _, p := range event.Params {
2275+
if p.Key == "data" {
2276+
height = parseI64(p.Value, height)
2277+
break
2278+
}
2279+
}
2280+
}
2281+
lastCommited, err := GetLastBlockIndex()
2282+
if err != nil {
2283+
return err
2284+
}
2285+
if height == 0 {
2286+
height = lastCommited
2287+
}
2288+
2289+
LoggerInfo("rolling back block", []string{"height", fmt.Sprintf("%d", height), "lastCommited", fmt.Sprintf("%d", lastCommited)})
2290+
2291+
if height > lastCommited+1 {
2292+
return nil
2293+
}
2294+
if height < lastCommited {
2295+
Revert(fmt.Sprintf(`must roll back last block first: %d`, height))
2296+
}
2297+
2298+
newHeight := height - 1
2299+
2300+
if height == lastCommited {
2301+
LoggerInfo("rolling back block", []string{"height", fmt.Sprint(height)})
2302+
2303+
data, err := getFinalBlock(height)
2304+
if err != nil {
2305+
return err
2306+
}
2307+
if data == "" {
2308+
return nil
2309+
}
2310+
2311+
var blockData blocks.BlockEntry
2312+
if err := json.Unmarshal([]byte(data), &blockData); err != nil {
2313+
return fmt.Errorf("failed to parse BlockEntry: %v", err)
2314+
}
2315+
2316+
var processReqWithMeta typestnd.RequestProcessProposalWithMetaInfo
2317+
if err := json.Unmarshal(blockData.Data, &processReqWithMeta); err != nil {
2318+
return fmt.Errorf("failed to unmarshal RequestProcessProposalWithMetaInfo: %v", err)
2319+
}
2320+
processReq := processReqWithMeta.Request
2321+
2322+
var finalizeResp typestnd.ResponseFinalizeBlock
2323+
if err := json.Unmarshal(blockData.Result, &finalizeResp); err != nil {
2324+
return fmt.Errorf("failed to unmarshal ResponseFinalizeBlock: %v", err)
2325+
}
2326+
2327+
var blockCommit typestnd.BlockCommit
2328+
if err := json.Unmarshal(blockData.LastCommit, &blockCommit); err != nil {
2329+
return fmt.Errorf("failed to unmarshal BlockCommit: %v", err)
2330+
}
2331+
2332+
var header typestnd.Header
2333+
if err := json.Unmarshal(blockData.Header, &header); err != nil {
2334+
return fmt.Errorf("failed to unmarshal Header: %v", err)
2335+
}
2336+
2337+
hash, err := consutils.GetHeaderHash(header)
2338+
if err != nil {
2339+
return err
2340+
}
2341+
2342+
// Rollback block from storage
2343+
var txhashes [][]byte
2344+
for _, tx := range processReq.Txs {
2345+
txhash := wasmx.Sha256(tx)
2346+
txhashes = append(txhashes, txhash)
2347+
}
2348+
indexedTopics := extractIndexedTopics(finalizeResp.TxResults, txhashes)
2349+
2350+
RollbackBlockData(height, hash, txhashes, indexedTopics)
2351+
LoggerInfo("rolled back block data", []string{"height", fmt.Sprint(height)})
2352+
2353+
// Update consensus state
2354+
lastCommitHash, _ := hex.DecodeString(strings.ToLower(string(header.LastCommitHash)))
2355+
lastResultsHash, _ := hex.DecodeString(strings.ToLower(string(header.LastResultsHash)))
2356+
2357+
state, err := GetCurrentState()
2358+
if err != nil {
2359+
return err
2360+
}
2361+
state.NextHeight = height
2362+
state.NextHash = []byte{}
2363+
state.AppHash = finalizeResp.AppHash
2364+
state.LastBlockID = GetBlockID(hash)
2365+
state.LastCommitHash = lastCommitHash
2366+
state.LastResultsHash = lastResultsHash
2367+
state.LastTime = processReq.Time
2368+
state.ValidValue = 0
2369+
state.ValidRound = 0
2370+
state.LockedValue = 0
2371+
state.LockedRound = 0
2372+
// state.LastBlockSignatures = blockCommit.Signatures
2373+
2374+
SetCurrentState(state)
2375+
LoggerInfo("rolledback consensus state", []string{"new_height", fmt.Sprint(newHeight), "app_hash", hex.EncodeToString(state.AppHash)})
2376+
}
2377+
2378+
// Reset indexes
2379+
RemoveLogEntry(height)
2380+
SetLastLogIndex(newHeight)
2381+
LoggerInfo("rolled back consensus data", []string{"new_height", fmt.Sprint(newHeight)})
2382+
2383+
LoggerInfo("rollback consensus completed", []string{"new_height", fmt.Sprint(newHeight)})
2384+
return nil
2385+
}

tests/testdata/tinygo/wasmx-raftp2p-lib/cmd/main.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,11 @@ func main() {
313313
lib.Revert("VerifyCommitLight failed: " + err.Error())
314314
return
315315
}
316+
case "rollback":
317+
if err := raft.Rollback(calld.Params, calld.Event); err != nil {
318+
lib.Revert("Rollback failed: " + err.Error())
319+
return
320+
}
316321
default:
317322
wasmx.Revert(append([]byte("invalid function call data: "), databz...))
318323
return

wasmx/server/rollback.go

Lines changed: 46 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,26 @@
11
package server
22

33
import (
4+
"context"
45
"fmt"
56

67
"github.com/spf13/cobra"
78

89
"github.com/cosmos/cosmos-sdk/client/flags"
910
sdkserver "github.com/cosmos/cosmos-sdk/server"
1011
"github.com/cosmos/cosmos-sdk/server/types"
12+
sdk "github.com/cosmos/cosmos-sdk/types"
1113

1214
mapp "github.com/loredanacirstea/wasmx/app"
1315
"github.com/loredanacirstea/wasmx/multichain"
16+
networktypes "github.com/loredanacirstea/wasmx/x/network/types"
17+
wasmxtypes "github.com/loredanacirstea/wasmx/x/wasmx/types"
1418
)
1519

16-
// NewRollbackCmd creates a command to rollback CometBFT and multistore state by one height.
20+
// NewRollbackCmd creates a command to rollback block, and multistore state by one height.
1721
func NewRollbackCmd(appCreator types.AppCreator, defaultNodeHome string) *cobra.Command {
18-
var removeBlock bool
22+
// var removeBlock bool
23+
var blockHeightPtr *int64
1924

2025
cmd := &cobra.Command{
2126
Use: "rollback",
@@ -37,31 +42,55 @@ application.
3742
return err
3843
}
3944
app := appCreator(ctx.Logger, db, nil, ctx.Viper)
40-
// TODO maybe rollback blocks too?
41-
// // rollback CometBFT state
42-
// height, hash, err := cmtcmd.RollbackState(ctx.Config, removeBlock)
43-
// if err != nil {
44-
// return fmt.Errorf("failed to rollback CometBFT state: %w", err)
45-
// }
46-
4745
baseapp := app.(*mapp.App)
48-
height := baseapp.LastBlockHeight() - 1
49-
fmt.Printf("rolling back to version: %d \n", height)
50-
51-
// rollback the multistore
52-
if err := app.CommitMultiStore().RollbackToVersion(height); err != nil {
53-
return fmt.Errorf("failed to rollback to version: %w", err)
46+
height := baseapp.LastBlockHeight()
47+
newheight := height - 1
48+
blockHeight := int64(0)
49+
if blockHeightPtr != nil {
50+
blockHeight = *blockHeightPtr
51+
}
52+
if blockHeight == int64(0) {
53+
blockHeight = height
54+
}
55+
if blockHeight < height {
56+
return fmt.Errorf("can only roll back last block: %d", height)
57+
}
58+
if blockHeight == height {
59+
fmt.Printf("rolling back to version: %d \n", newheight)
60+
// rollback the multistore
61+
if err := app.CommitMultiStore().RollbackToVersion(newheight); err != nil {
62+
return fmt.Errorf("failed to rollback to version: %w", err)
63+
}
5464
}
5565

5666
height = baseapp.LastBlockHeight()
5767
hash := baseapp.LastCommitID().Hash
5868
fmt.Printf("Rolled back state to height %d and hash %X", height, hash)
59-
return nil
69+
70+
_, goctx := getCtx(ctx, true)
71+
cb := func(goctx context.Context) (any, error) {
72+
ctx := sdk.UnwrapSDKContext(goctx)
73+
msg := []byte(fmt.Sprintf(`{"execute":{"action": {"type": "rollback", "params": [{"key":"height","value":"%d"}],"event":null}}}`, blockHeight))
74+
execmsg := &networktypes.MsgExecuteContract{
75+
Sender: wasmxtypes.ROLE_CONSENSUS,
76+
Contract: wasmxtypes.ROLE_CONSENSUS,
77+
Msg: msg,
78+
}
79+
res, err := baseapp.NetworkKeeper.ExecuteContractInternal(ctx, execmsg)
80+
if err != nil {
81+
return nil, err
82+
}
83+
return res, nil
84+
}
85+
86+
_, err = baseapp.GetActionExecutor().Execute(goctx, height, sdk.ExecModeFinalize, cb)
87+
return err
6088
},
6189
}
6290

6391
cmd.Flags().String(flags.FlagHome, defaultNodeHome, "The application home directory")
64-
cmd.Flags().BoolVar(&removeBlock, "hard", false, "remove last block as well as state")
92+
// cmd.Flags().BoolVar(&removeBlock, "hard", false, "remove last block as well as state")
93+
blockHeightPtr = cmd.Flags().Int64("height", 0, "block height to remove, optional")
6594
cmd.Flags().String(flags.FlagChainID, "testnet", "Specify Chain ID for sending Tx")
6695
cmd.Flags().String(multichain.FlagRegistryChainId, "", "multichain registry chain id")
6796
return cmd
9.39 KB
Binary file not shown.
216 Bytes
Binary file not shown.
5.26 KB
Binary file not shown.
20.4 KB
Binary file not shown.

0 commit comments

Comments
 (0)