github.com/Finschia/finschia-sdk@v0.48.1/server/mock/app.go (about)

     1  package mock
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"errors"
     7  	"fmt"
     8  	"path/filepath"
     9  
    10  	ocabci "github.com/Finschia/ostracon/abci/types"
    11  	"github.com/Finschia/ostracon/libs/log"
    12  	"github.com/Finschia/ostracon/types"
    13  	abci "github.com/tendermint/tendermint/abci/types"
    14  
    15  	bam "github.com/Finschia/finschia-sdk/baseapp"
    16  	"github.com/Finschia/finschia-sdk/codec"
    17  	storetypes "github.com/Finschia/finschia-sdk/store/types"
    18  	sdk "github.com/Finschia/finschia-sdk/types"
    19  )
    20  
    21  // NewApp creates a simple mock kvstore app for testing. It should work
    22  // similar to a real app. Make sure rootDir is empty before running the test,
    23  // in order to guarantee consistent results
    24  func NewApp(rootDir string, logger log.Logger) (ocabci.Application, error) {
    25  	db, err := sdk.NewLevelDB("mock", filepath.Join(rootDir, "data"))
    26  	if err != nil {
    27  		return nil, err
    28  	}
    29  
    30  	// Capabilities key to access the main KVStore.
    31  	capKeyMainStore := sdk.NewKVStoreKey("main")
    32  
    33  	// Create BaseApp.
    34  	baseApp := bam.NewBaseApp("kvstore", logger, db, decodeTx)
    35  
    36  	// Set mounts for BaseApp's MultiStore.
    37  	baseApp.MountStores(capKeyMainStore)
    38  
    39  	baseApp.SetInitChainer(InitChainer(capKeyMainStore))
    40  
    41  	baseApp.Router().AddRoute(sdk.NewRoute("kvstore", KVStoreHandler(capKeyMainStore)))
    42  
    43  	// Load latest version.
    44  	if err := baseApp.LoadLatestVersion(); err != nil {
    45  		return nil, err
    46  	}
    47  
    48  	return baseApp, nil
    49  }
    50  
    51  // KVStoreHandler is a simple handler that takes kvstoreTx and writes
    52  // them to the db
    53  func KVStoreHandler(storeKey sdk.StoreKey) sdk.Handler {
    54  	return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) {
    55  		dTx, ok := msg.(kvstoreTx)
    56  		if !ok {
    57  			return nil, errors.New("KVStoreHandler should only receive kvstoreTx")
    58  		}
    59  
    60  		// tx is already unmarshalled
    61  		key := dTx.key
    62  		value := dTx.value
    63  
    64  		store := ctx.KVStore(storeKey)
    65  		store.Set(key, value)
    66  
    67  		return &sdk.Result{
    68  			Log: fmt.Sprintf("set %s=%s", key, value),
    69  		}, nil
    70  	}
    71  }
    72  
    73  // basic KV structure
    74  type KV struct {
    75  	Key   string `json:"key"`
    76  	Value string `json:"value"`
    77  }
    78  
    79  // What Genesis JSON is formatted as
    80  type GenesisJSON struct {
    81  	Values []KV `json:"values"`
    82  }
    83  
    84  // InitChainer returns a function that can initialize the chain
    85  // with key/value pairs
    86  func InitChainer(key sdk.StoreKey) func(sdk.Context, abci.RequestInitChain) abci.ResponseInitChain {
    87  	return func(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain {
    88  		stateJSON := req.AppStateBytes
    89  
    90  		genesisState := new(GenesisJSON)
    91  		err := json.Unmarshal(stateJSON, genesisState)
    92  		if err != nil {
    93  			panic(err) // TODO https://github.com/cosmos/cosmos-sdk/issues/468
    94  			// return sdk.ErrGenesisParse("").TraceCause(err, "")
    95  		}
    96  
    97  		for _, val := range genesisState.Values {
    98  			store := ctx.KVStore(key)
    99  			store.Set([]byte(val.Key), []byte(val.Value))
   100  		}
   101  		return abci.ResponseInitChain{}
   102  	}
   103  }
   104  
   105  // AppGenState can be passed into InitCmd, returns a static string of a few
   106  // key-values that can be parsed by InitChainer
   107  func AppGenState(_ *codec.LegacyAmino, _ types.GenesisDoc, _ []json.RawMessage) (appState json.
   108  	RawMessage, err error,
   109  ) {
   110  	appState = json.RawMessage(`{
   111    "values": [
   112      {
   113          "key": "hello",
   114          "value": "goodbye"
   115      },
   116      {
   117          "key": "foo",
   118          "value": "bar"
   119      }
   120    ]
   121  }`)
   122  	return
   123  }
   124  
   125  // AppGenStateEmpty returns an empty transaction state for mocking.
   126  func AppGenStateEmpty(_ *codec.LegacyAmino, _ types.GenesisDoc, _ []json.RawMessage) (
   127  	appState json.RawMessage, err error,
   128  ) {
   129  	appState = json.RawMessage(``)
   130  	return
   131  }
   132  
   133  // Manually write the handlers for this custom message
   134  type MsgServer interface {
   135  	Test(ctx context.Context, msg *kvstoreTx) (*sdk.Result, error)
   136  }
   137  
   138  type MsgServerImpl struct {
   139  	capKeyMainStore *storetypes.KVStoreKey
   140  }
   141  
   142  func (m MsgServerImpl) Test(ctx context.Context, msg *kvstoreTx) (*sdk.Result, error) {
   143  	return KVStoreHandler(m.capKeyMainStore)(sdk.UnwrapSDKContext(ctx), msg)
   144  }