Skip to content

Commit

Permalink
Merge pull request #8060 from Agoric/mhofman/refactor-cosmos-init
Browse files Browse the repository at this point in the history
refactor cosmos init
  • Loading branch information
mhofman committed Aug 7, 2023
2 parents c70627b + fd678a5 commit 0ee45f1
Show file tree
Hide file tree
Showing 12 changed files with 277 additions and 253 deletions.
116 changes: 88 additions & 28 deletions golang/cosmos/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"net/http"
"os"
"path/filepath"
"runtime/debug"
"time"

"github.com/cosmos/cosmos-sdk/baseapp"
Expand All @@ -21,6 +22,7 @@ import (
servertypes "github.com/cosmos/cosmos-sdk/server/types"
"github.com/cosmos/cosmos-sdk/simapp"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/types/module"
"github.com/cosmos/cosmos-sdk/version"
"github.com/cosmos/cosmos-sdk/x/auth"
Expand Down Expand Up @@ -196,6 +198,7 @@ type GaiaApp struct { // nolint: golint
interfaceRegistry types.InterfaceRegistry

controllerInited bool
bootstrapNeeded bool
lienPort int
vbankPort int
vibcPort int
Expand Down Expand Up @@ -431,17 +434,20 @@ func NewAgoricApp(

// This function is tricky to get right, so we build it ourselves.
callToController := func(ctx sdk.Context, str string) (string, error) {
app.CheckControllerInited(true)
// We use SwingSet-level metering to charge the user for the call.
app.MustInitController(ctx)
defer vm.SetControllerContext(ctx)()
return sendToController(true, str)
}

setBootstrapNeeded := func() {
app.bootstrapNeeded = true
}

app.VstorageKeeper = vstorage.NewKeeper(
keys[vstorage.StoreKey],
)
vm.RegisterPortHandler("vstorage", vstorage.NewStorageHandler(app.VstorageKeeper))
app.vstoragePort = vm.GetPort("vstorage")
app.vstoragePort = vm.RegisterPortHandler("vstorage", vstorage.NewStorageHandler(app.VstorageKeeper))

// The SwingSetKeeper is the Keeper from the SwingSet module
app.SwingSetKeeper = swingset.NewKeeper(
Expand All @@ -453,8 +459,18 @@ func NewAgoricApp(

app.SwingSetSnapshotter = swingsetkeeper.NewSwingsetSnapshotter(
bApp,
app.SwingSetKeeper,
sendToController,
app.SwingSetKeeper.ExportSwingStore,
func(action vm.Jsonable, mustNotBeInited bool) (string, error) {
if mustNotBeInited {
app.CheckControllerInited(false)
}

bz, err := json.Marshal(action)
if err != nil {
return "", err
}
return sendToController(true, string(bz))
},
)

app.VibcKeeper = vibc.NewKeeper(
Expand Down Expand Up @@ -582,7 +598,7 @@ func NewAgoricApp(
transferModule,
icaModule,
vstorage.NewAppModule(app.VstorageKeeper),
swingset.NewAppModule(app.SwingSetKeeper),
swingset.NewAppModule(app.SwingSetKeeper, setBootstrapNeeded),
vibcModule,
vbankModule,
lienModule,
Expand Down Expand Up @@ -809,57 +825,91 @@ func normalizeModuleAccount(ctx sdk.Context, ak authkeeper.AccountKeeper, name s
type cosmosInitAction struct {
Type string `json:"type"`
ChainID string `json:"chainID"`
IsBootstrap bool `json:"isBootstrap"`
Params swingset.Params `json:"params"`
StoragePort int `json:"storagePort"`
SupplyCoins sdk.Coins `json:"supplyCoins"`
VibcPort int `json:"vibcPort"`
VbankPort int `json:"vbankPort"`
LienPort int `json:"lienPort"`
UpgradePlan *upgradetypes.Plan `json:"upgradePlan,omitempty"`
LienPort int `json:"lienPort"`
StoragePort int `json:"storagePort"`
VbankPort int `json:"vbankPort"`
VibcPort int `json:"vibcPort"`
}

// Name returns the name of the App
func (app *GaiaApp) Name() string { return app.BaseApp.Name() }

func (app *GaiaApp) MustInitController(ctx sdk.Context) {
if app.controllerInited {
return
// CheckControllerInited exits if the controller initialization state does not match `expected`.
func (app *GaiaApp) CheckControllerInited(expected bool) {
if app.controllerInited != expected {
fmt.Fprintf(os.Stderr, "controllerInited != %t\n", expected)
debug.PrintStack()
os.Exit(1)
}
}

// initController sends the initialization message to the VM.
// Exits if the controller has already been initialized.
func (app *GaiaApp) initController(ctx sdk.Context, bootstrap bool) {
app.CheckControllerInited(false)
app.controllerInited = true
// Begin initializing the controller here.
action := &cosmosInitAction{
Type: "AG_COSMOS_INIT",
ChainID: ctx.ChainID(),
IsBootstrap: bootstrap,
Params: app.SwingSetKeeper.GetParams(ctx),
StoragePort: app.vstoragePort,
SupplyCoins: sdk.NewCoins(app.BankKeeper.GetSupply(ctx, "uist")),
VibcPort: app.vibcPort,
VbankPort: app.vbankPort,
LienPort: app.lienPort,
UpgradePlan: app.upgradePlan,
LienPort: app.lienPort,
StoragePort: app.vstoragePort,
VbankPort: app.vbankPort,
VibcPort: app.vibcPort,
}
// This really abuses `BlockingSend` to get back at `sendToController`
out, err := app.SwingSetKeeper.BlockingSend(ctx, action)

// fmt.Fprintf(os.Stderr, "AG_COSMOS_INIT Returned from SwingSet: %s, %v\n", out, err)

if err != nil {
fmt.Fprintln(os.Stderr, "Cannot initialize Controller", err)
os.Exit(1)
panic(errors.Wrap(err, "cannot initialize Controller"))
}
var res bool
err = json.Unmarshal([]byte(out), &res)
if err != nil {
fmt.Fprintln(os.Stderr, "Cannot unmarshal Controller init response", out, err)
os.Exit(1)
panic(errors.Wrapf(err, "cannot unmarshal Controller init response: %s", out))
}
if !res {
fmt.Fprintln(os.Stderr, "Controller negative init response")
os.Exit(1)
panic(fmt.Errorf("controller negative init response"))
}
}

type bootstrapBlockAction struct {
Type string `json:"type"`
BlockTime int64 `json:"blockTime"`
}

// BootstrapController initializes the controller (with the bootstrap flag) and sends a bootstrap action.
func (app *GaiaApp) BootstrapController(ctx sdk.Context) error {
app.initController(ctx, true)

stdlog.Println("Running SwingSet until bootstrap is ready")
// Just run the SwingSet kernel to finish bootstrap and get ready to open for
// business.
action := &bootstrapBlockAction{
Type: "BOOTSTRAP_BLOCK",
BlockTime: ctx.BlockTime().Unix(),
}

_, err := app.SwingSetKeeper.BlockingSend(ctx, action)
return err
}

// BeginBlocker application updates every begin block
func (app *GaiaApp) BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock) abci.ResponseBeginBlock {
if !app.controllerInited {
app.initController(ctx, false)
}

return app.mm.BeginBlock(ctx, req)
}

Expand All @@ -878,18 +928,28 @@ func (app *GaiaApp) InitChainer(ctx sdk.Context, req abci.RequestInitChain) abci
app.UpgradeKeeper.SetModuleVersionMap(ctx, app.mm.GetVersionMap())
res := app.mm.InitGenesis(ctx, app.appCodec, genesisState)

// initialize the provision and reserve module accounts, to avoid their implicit creation
// as a default account upon receiving a transfer. See BlockedAddrs().
normalizeModuleAccount(ctx, app.AccountKeeper, vbanktypes.ProvisionPoolName)
normalizeModuleAccount(ctx, app.AccountKeeper, vbanktypes.ReservePoolName)

if app.bootstrapNeeded {
err := app.BootstrapController(ctx)
// fmt.Fprintf(os.Stderr, "BOOTSTRAP_BLOCK Returned from swingset: %s, %v\n", out, err)
if err != nil {
// NOTE: A failed BOOTSTRAP_BLOCK means that the SwingSet state is inconsistent.
// Panic here, in the hopes that a replay from scratch will fix the problem.
panic(err)
}
}

// Agoric: report the genesis time explicitly.
genTime := req.GetTime()
if genTime.After(time.Now()) {
d := time.Until(genTime)
stdlog.Printf("Genesis time %s is in %s\n", genTime, d)
}

// initialize the provision and reserve module accounts, to avoid their implicit creation
// as a default account upon receiving a transfer. See BockedAddrs().
normalizeModuleAccount(ctx, app.AccountKeeper, vbanktypes.ProvisionPoolName)
normalizeModuleAccount(ctx, app.AccountKeeper, vbanktypes.ReservePoolName)

return res
}

Expand Down
3 changes: 1 addition & 2 deletions golang/cosmos/vm/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (

type ControllerContext struct {
Context sdk.Context
StoragePort int
IBCChannelHandlerPort int
}

Expand Down Expand Up @@ -74,7 +73,7 @@ func UnregisterPortHandler(portNum int) error {
func ReceiveFromController(portNum int, msg string) (string, error) {
handler := portToHandler[portNum]
if handler == nil {
return "", fmt.Errorf("Unregistered port %d", portNum)
return "", fmt.Errorf("unregistered port %d", portNum)
}
return handler.Receive(&controllerContext, msg)
}
3 changes: 0 additions & 3 deletions golang/cosmos/x/swingset/abci.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,11 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
abci "github.com/tendermint/tendermint/abci/types"

"github.com/Agoric/agoric-sdk/golang/cosmos/vm"
"github.com/Agoric/agoric-sdk/golang/cosmos/x/swingset/types"
)

type beginBlockAction struct {
Type string `json:"type"`
StoragePort int `json:"storagePort"`
BlockHeight int64 `json:"blockHeight"`
BlockTime int64 `json:"blockTime"`
ChainID string `json:"chainID"`
Expand All @@ -39,7 +37,6 @@ func BeginBlock(ctx sdk.Context, req abci.RequestBeginBlock, keeper Keeper) erro

action := &beginBlockAction{
Type: "BEGIN_BLOCK",
StoragePort: vm.GetPort("vstorage"),
BlockHeight: ctx.BlockHeight(),
BlockTime: ctx.BlockTime().Unix(),
ChainID: ctx.ChainID(),
Expand Down
39 changes: 5 additions & 34 deletions golang/cosmos/x/swingset/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,9 @@ package swingset
import (
// "os"
"fmt"
stdlog "log"

"github.com/Agoric/agoric-sdk/golang/cosmos/vm"
"github.com/Agoric/agoric-sdk/golang/cosmos/x/swingset/types"
sdk "github.com/cosmos/cosmos-sdk/types"
abci "github.com/tendermint/tendermint/abci/types"
)

func NewGenesisState() *types.GenesisState {
Expand All @@ -31,40 +28,14 @@ func DefaultGenesisState() *types.GenesisState {
}
}

type bootstrapBlockAction struct {
Type string `json:"type"`
BlockTime int64 `json:"blockTime"`
StoragePort int `json:"storagePort"`
}

func BootSwingset(ctx sdk.Context, keeper Keeper) error {
// Just run the SwingSet kernel to finish bootstrap and get ready to open for
// business.
action := &bootstrapBlockAction{
Type: "BOOTSTRAP_BLOCK",
BlockTime: ctx.BlockTime().Unix(),
StoragePort: vm.GetPort("vstorage"),
}

_, err := keeper.BlockingSend(ctx, action)
return err
}

func InitGenesis(ctx sdk.Context, keeper Keeper, data *types.GenesisState) []abci.ValidatorUpdate {
// InitGenesis initializes the (Cosmos-side) SwingSet state from the GenesisState.
// Returns whether the app should send a bootstrap action to the controller.
func InitGenesis(ctx sdk.Context, keeper Keeper, data *types.GenesisState) bool {
keeper.SetParams(ctx, data.GetParams())
keeper.SetState(ctx, data.GetState())

stdlog.Println("Running SwingSet until bootstrap is ready")
err := BootSwingset(ctx, keeper)

// fmt.Fprintf(os.Stderr, "BOOTSTRAP_BLOCK Returned from swingset: %s, %v\n", out, err)
if err != nil {
// NOTE: A failed BOOTSTRAP_BLOCK means that the SwingSet state is inconsistent.
// Panic here, in the hopes that a replay from scratch will fix the problem.
panic(err)
}

return []abci.ValidatorUpdate{}
// TODO: bootstrap only if not restoring swing-store from genesis state
return true
}

func ExportGenesis(ctx sdk.Context, k Keeper) *types.GenesisState {
Expand Down
2 changes: 0 additions & 2 deletions golang/cosmos/x/swingset/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ type deliverInboundAction struct {
Peer string `json:"peer"`
Messages [][]interface{} `json:"messages"`
Ack uint64 `json:"ack"`
StoragePort int `json:"storagePort"`
BlockHeight int64 `json:"blockHeight"`
BlockTime int64 `json:"blockTime"`
}
Expand Down Expand Up @@ -58,7 +57,6 @@ func (keeper msgServer) DeliverInbound(goCtx context.Context, msg *types.MsgDeli
Peer: msg.Submitter.String(),
Messages: messages,
Ack: msg.Ack,
StoragePort: vm.GetPort("vstorage"),
BlockHeight: ctx.BlockHeight(),
BlockTime: ctx.BlockTime().Unix(),
}
Expand Down
Loading

0 comments on commit 0ee45f1

Please sign in to comment.