Merge branch 'master' of https://github.com/cosmos/cosmos-sdk into aditya/cleanup
This commit is contained in:
@@ -0,0 +1,229 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
cmn "github.com/tendermint/tendermint/libs/common"
|
||||
dbm "github.com/tendermint/tendermint/libs/db"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
|
||||
bapp "github.com/cosmos/cosmos-sdk/baseapp"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
const (
|
||||
app1Name = "App1"
|
||||
)
|
||||
|
||||
func NewApp1(logger log.Logger, db dbm.DB) *bapp.BaseApp {
|
||||
|
||||
// Create the base application object.
|
||||
app := bapp.NewBaseAppNoCodec(app1Name, logger, db, tx1Decoder)
|
||||
|
||||
// Create a key for accessing the account store.
|
||||
keyAccount := sdk.NewKVStoreKey("acc")
|
||||
|
||||
// Register message routes.
|
||||
// Note the handler gets access to the account store.
|
||||
app.Router().
|
||||
AddRoute("send", handleMsgSend(keyAccount))
|
||||
|
||||
// Mount stores and load the latest state.
|
||||
app.MountStoresIAVL(keyAccount)
|
||||
err := app.LoadLatestVersion(keyAccount)
|
||||
if err != nil {
|
||||
cmn.Exit(err.Error())
|
||||
}
|
||||
return app
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Msg
|
||||
|
||||
// MsgSend implements sdk.Msg
|
||||
var _ sdk.Msg = MsgSend{}
|
||||
|
||||
// MsgSend to send coins from Input to Output
|
||||
type MsgSend struct {
|
||||
From sdk.AccAddress `json:"from"`
|
||||
To sdk.AccAddress `json:"to"`
|
||||
Amount sdk.Coins `json:"amount"`
|
||||
}
|
||||
|
||||
// NewMsgSend
|
||||
func NewMsgSend(from, to sdk.AccAddress, amt sdk.Coins) MsgSend {
|
||||
return MsgSend{from, to, amt}
|
||||
}
|
||||
|
||||
// Implements Msg.
|
||||
func (msg MsgSend) Type() string { return "send" }
|
||||
|
||||
// Implements Msg. Ensure the addresses are good and the
|
||||
// amount is positive.
|
||||
func (msg MsgSend) ValidateBasic() sdk.Error {
|
||||
if len(msg.From) == 0 {
|
||||
return sdk.ErrInvalidAddress("From address is empty")
|
||||
}
|
||||
if len(msg.To) == 0 {
|
||||
return sdk.ErrInvalidAddress("To address is empty")
|
||||
}
|
||||
if !msg.Amount.IsPositive() {
|
||||
return sdk.ErrInvalidCoins("Amount is not positive")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Implements Msg. JSON encode the message.
|
||||
func (msg MsgSend) GetSignBytes() []byte {
|
||||
bz, err := json.Marshal(msg)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return sdk.MustSortJSON(bz)
|
||||
}
|
||||
|
||||
// Implements Msg. Return the signer.
|
||||
func (msg MsgSend) GetSigners() []sdk.AccAddress {
|
||||
return []sdk.AccAddress{msg.From}
|
||||
}
|
||||
|
||||
// Returns the sdk.Tags for the message
|
||||
func (msg MsgSend) Tags() sdk.Tags {
|
||||
return sdk.NewTags("sender", []byte(msg.From.String())).
|
||||
AppendTag("receiver", []byte(msg.To.String()))
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Handler for the message
|
||||
|
||||
// Handle MsgSend.
|
||||
// NOTE: msg.From, msg.To, and msg.Amount were already validated
|
||||
// in ValidateBasic().
|
||||
func handleMsgSend(key *sdk.KVStoreKey) sdk.Handler {
|
||||
return func(ctx sdk.Context, msg sdk.Msg) sdk.Result {
|
||||
sendMsg, ok := msg.(MsgSend)
|
||||
if !ok {
|
||||
// Create custom error message and return result
|
||||
// Note: Using unreserved error codespace
|
||||
return sdk.NewError(2, 1, "MsgSend is malformed").Result()
|
||||
}
|
||||
|
||||
// Load the store.
|
||||
store := ctx.KVStore(key)
|
||||
|
||||
// Debit from the sender.
|
||||
if res := handleFrom(store, sendMsg.From, sendMsg.Amount); !res.IsOK() {
|
||||
return res
|
||||
}
|
||||
|
||||
// Credit the receiver.
|
||||
if res := handleTo(store, sendMsg.To, sendMsg.Amount); !res.IsOK() {
|
||||
return res
|
||||
}
|
||||
|
||||
// Return a success (Code 0).
|
||||
// Add list of key-value pair descriptors ("tags").
|
||||
return sdk.Result{
|
||||
Tags: sendMsg.Tags(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Convenience Handlers
|
||||
func handleFrom(store sdk.KVStore, from sdk.AccAddress, amt sdk.Coins) sdk.Result {
|
||||
// Get sender account from the store.
|
||||
accBytes := store.Get(from)
|
||||
if accBytes == nil {
|
||||
// Account was not added to store. Return the result of the error.
|
||||
return sdk.NewError(2, 101, "Account not added to store").Result()
|
||||
}
|
||||
|
||||
// Unmarshal the JSON account bytes.
|
||||
var acc appAccount
|
||||
err := json.Unmarshal(accBytes, &acc)
|
||||
if err != nil {
|
||||
// InternalError
|
||||
return sdk.ErrInternal("Error when deserializing account").Result()
|
||||
}
|
||||
|
||||
// Deduct msg amount from sender account.
|
||||
senderCoins := acc.Coins.Minus(amt)
|
||||
|
||||
// If any coin has negative amount, return insufficient coins error.
|
||||
if !senderCoins.IsNotNegative() {
|
||||
return sdk.ErrInsufficientCoins("Insufficient coins in account").Result()
|
||||
}
|
||||
|
||||
// Set acc coins to new amount.
|
||||
acc.Coins = senderCoins
|
||||
|
||||
// Encode sender account.
|
||||
accBytes, err = json.Marshal(acc)
|
||||
if err != nil {
|
||||
return sdk.ErrInternal("Account encoding error").Result()
|
||||
}
|
||||
|
||||
// Update store with updated sender account
|
||||
store.Set(from, accBytes)
|
||||
return sdk.Result{}
|
||||
}
|
||||
|
||||
func handleTo(store sdk.KVStore, to sdk.AccAddress, amt sdk.Coins) sdk.Result {
|
||||
// Add msg amount to receiver account
|
||||
accBytes := store.Get(to)
|
||||
var acc appAccount
|
||||
if accBytes == nil {
|
||||
// Receiver account does not already exist, create a new one.
|
||||
acc = appAccount{}
|
||||
} else {
|
||||
// Receiver account already exists. Retrieve and decode it.
|
||||
err := json.Unmarshal(accBytes, &acc)
|
||||
if err != nil {
|
||||
return sdk.ErrInternal("Account decoding error").Result()
|
||||
}
|
||||
}
|
||||
|
||||
// Add amount to receiver's old coins
|
||||
receiverCoins := acc.Coins.Plus(amt)
|
||||
|
||||
// Update receiver account
|
||||
acc.Coins = receiverCoins
|
||||
|
||||
// Encode receiver account
|
||||
accBytes, err := json.Marshal(acc)
|
||||
if err != nil {
|
||||
return sdk.ErrInternal("Account encoding error").Result()
|
||||
}
|
||||
|
||||
// Update store with updated receiver account
|
||||
store.Set(to, accBytes)
|
||||
return sdk.Result{}
|
||||
}
|
||||
|
||||
// Simple account struct
|
||||
type appAccount struct {
|
||||
Coins sdk.Coins `json:"coins"`
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Tx
|
||||
|
||||
// Simple tx to wrap the Msg.
|
||||
type app1Tx struct {
|
||||
MsgSend
|
||||
}
|
||||
|
||||
// This tx only has one Msg.
|
||||
func (tx app1Tx) GetMsgs() []sdk.Msg {
|
||||
return []sdk.Msg{tx.MsgSend}
|
||||
}
|
||||
|
||||
// JSON decode MsgSend.
|
||||
func tx1Decoder(txBytes []byte) (sdk.Tx, sdk.Error) {
|
||||
var tx app1Tx
|
||||
err := json.Unmarshal(txBytes, &tx)
|
||||
if err != nil {
|
||||
return nil, sdk.ErrTxDecode(err.Error())
|
||||
}
|
||||
return tx, nil
|
||||
}
|
||||
@@ -0,0 +1,243 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
cmn "github.com/tendermint/tendermint/libs/common"
|
||||
dbm "github.com/tendermint/tendermint/libs/db"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
|
||||
bapp "github.com/cosmos/cosmos-sdk/baseapp"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/wire"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
)
|
||||
|
||||
const (
|
||||
app2Name = "App2"
|
||||
)
|
||||
|
||||
var (
|
||||
issuer = crypto.GenPrivKeyEd25519().PubKey().Address()
|
||||
)
|
||||
|
||||
func NewCodec() *wire.Codec {
|
||||
cdc := wire.NewCodec()
|
||||
cdc.RegisterInterface((*sdk.Msg)(nil), nil)
|
||||
cdc.RegisterConcrete(MsgSend{}, "example/MsgSend", nil)
|
||||
cdc.RegisterConcrete(MsgIssue{}, "example/MsgIssue", nil)
|
||||
return cdc
|
||||
}
|
||||
|
||||
func NewApp2(logger log.Logger, db dbm.DB) *bapp.BaseApp {
|
||||
|
||||
cdc := NewCodec()
|
||||
|
||||
// Create the base application object.
|
||||
app := bapp.NewBaseAppNoCodec(app2Name, logger, db, tx2Decoder(cdc))
|
||||
|
||||
// Create a key for accessing the account store.
|
||||
keyAccount := sdk.NewKVStoreKey("acc")
|
||||
// Create a key for accessing the issue store.
|
||||
keyIssue := sdk.NewKVStoreKey("issue")
|
||||
|
||||
// set antehandler function
|
||||
app.SetAnteHandler(antehandler)
|
||||
|
||||
// Register message routes.
|
||||
// Note the handler gets access to the account store.
|
||||
app.Router().
|
||||
AddRoute("send", handleMsgSend(keyAccount)).
|
||||
AddRoute("issue", handleMsgIssue(keyAccount, keyIssue))
|
||||
|
||||
// Mount stores and load the latest state.
|
||||
app.MountStoresIAVL(keyAccount, keyIssue)
|
||||
err := app.LoadLatestVersion(keyAccount)
|
||||
if err != nil {
|
||||
cmn.Exit(err.Error())
|
||||
}
|
||||
return app
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Msgs
|
||||
|
||||
// MsgIssue to allow a registered issuer
|
||||
// to issue new coins.
|
||||
type MsgIssue struct {
|
||||
Issuer sdk.AccAddress
|
||||
Receiver sdk.AccAddress
|
||||
Coin sdk.Coin
|
||||
}
|
||||
|
||||
// Implements Msg.
|
||||
func (msg MsgIssue) Type() string { return "issue" }
|
||||
|
||||
// Implements Msg. Ensures addresses are valid and Coin is positive
|
||||
func (msg MsgIssue) ValidateBasic() sdk.Error {
|
||||
if len(msg.Issuer) == 0 {
|
||||
return sdk.ErrInvalidAddress("Issuer address cannot be empty")
|
||||
}
|
||||
|
||||
if len(msg.Receiver) == 0 {
|
||||
return sdk.ErrInvalidAddress("Receiver address cannot be empty")
|
||||
}
|
||||
|
||||
// Cannot issue zero or negative coins
|
||||
if !msg.Coin.IsPositive() {
|
||||
return sdk.ErrInvalidCoins("Cannot issue 0 or negative coin amounts")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Implements Msg. Get canonical sign bytes for MsgIssue
|
||||
func (msg MsgIssue) GetSignBytes() []byte {
|
||||
bz, err := json.Marshal(msg)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return sdk.MustSortJSON(bz)
|
||||
}
|
||||
|
||||
// Implements Msg. Return the signer.
|
||||
func (msg MsgIssue) GetSigners() []sdk.AccAddress {
|
||||
return []sdk.AccAddress{msg.Issuer}
|
||||
}
|
||||
|
||||
// Returns the sdk.Tags for the message
|
||||
func (msg MsgIssue) Tags() sdk.Tags {
|
||||
return sdk.NewTags("issuer", []byte(msg.Issuer.String())).
|
||||
AppendTag("receiver", []byte(msg.Receiver.String()))
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Handler for the message
|
||||
|
||||
// Handle MsgIssue.
|
||||
func handleMsgIssue(keyIssue *sdk.KVStoreKey, keyAcc *sdk.KVStoreKey) sdk.Handler {
|
||||
return func(ctx sdk.Context, msg sdk.Msg) sdk.Result {
|
||||
issueMsg, ok := msg.(MsgIssue)
|
||||
if !ok {
|
||||
return sdk.NewError(2, 1, "MsgIssue is malformed").Result()
|
||||
}
|
||||
|
||||
// Retrieve stores
|
||||
issueStore := ctx.KVStore(keyIssue)
|
||||
accStore := ctx.KVStore(keyAcc)
|
||||
|
||||
// Handle updating coin info
|
||||
if res := handleIssuer(issueStore, issueMsg.Issuer, issueMsg.Coin); !res.IsOK() {
|
||||
return res
|
||||
}
|
||||
|
||||
// Issue coins to receiver using previously defined handleTo function
|
||||
if res := handleTo(accStore, issueMsg.Receiver, []sdk.Coin{issueMsg.Coin}); !res.IsOK() {
|
||||
return res
|
||||
}
|
||||
|
||||
return sdk.Result{
|
||||
// Return result with Issue msg tags
|
||||
Tags: issueMsg.Tags(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func handleIssuer(store sdk.KVStore, issuer sdk.AccAddress, coin sdk.Coin) sdk.Result {
|
||||
// the issuer address is stored directly under the coin denomination
|
||||
denom := []byte(coin.Denom)
|
||||
infoBytes := store.Get(denom)
|
||||
if infoBytes == nil {
|
||||
return sdk.ErrInvalidCoins(fmt.Sprintf("Unknown coin type %s", coin.Denom)).Result()
|
||||
}
|
||||
|
||||
var coinInfo coinInfo
|
||||
err := json.Unmarshal(infoBytes, &coinInfo)
|
||||
if err != nil {
|
||||
return sdk.ErrInternal("Error when deserializing coinInfo").Result()
|
||||
}
|
||||
|
||||
// Msg Issuer is not authorized to issue these coins
|
||||
if !bytes.Equal(coinInfo.Issuer, issuer) {
|
||||
return sdk.ErrUnauthorized(fmt.Sprintf("Msg Issuer cannot issue tokens: %s", coin.Denom)).Result()
|
||||
}
|
||||
|
||||
return sdk.Result{}
|
||||
}
|
||||
|
||||
// coinInfo stores meta data about a coin
|
||||
type coinInfo struct {
|
||||
Issuer sdk.AccAddress `json:"issuer"`
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Tx
|
||||
|
||||
// Simple tx to wrap the Msg.
|
||||
type app2Tx struct {
|
||||
sdk.Msg
|
||||
Signatures []auth.StdSignature
|
||||
}
|
||||
|
||||
// This tx only has one Msg.
|
||||
func (tx app2Tx) GetMsgs() []sdk.Msg {
|
||||
return []sdk.Msg{tx.Msg}
|
||||
}
|
||||
|
||||
func (tx app2Tx) GetSignatures() []auth.StdSignature {
|
||||
return tx.Signatures
|
||||
}
|
||||
|
||||
// Amino decode app2Tx. Capable of decoding both MsgSend and MsgIssue
|
||||
func tx2Decoder(cdc *wire.Codec) sdk.TxDecoder {
|
||||
return func(txBytes []byte) (sdk.Tx, sdk.Error) {
|
||||
var tx app2Tx
|
||||
err := cdc.UnmarshalBinary(txBytes, &tx)
|
||||
if err != nil {
|
||||
return nil, sdk.ErrTxDecode(err.Error())
|
||||
}
|
||||
return tx, nil
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
|
||||
// Simple anteHandler that ensures msg signers have signed.
|
||||
// Provides no replay protection.
|
||||
func antehandler(ctx sdk.Context, tx sdk.Tx) (_ sdk.Context, _ sdk.Result, abort bool) {
|
||||
appTx, ok := tx.(app2Tx)
|
||||
if !ok {
|
||||
// set abort boolean to true so that we don't continue to process failed tx
|
||||
return ctx, sdk.ErrTxDecode("Tx must be of format app2Tx").Result(), true
|
||||
}
|
||||
|
||||
// expect only one msg in app2Tx
|
||||
msg := tx.GetMsgs()[0]
|
||||
|
||||
signerAddrs := msg.GetSigners()
|
||||
|
||||
if len(signerAddrs) != len(appTx.GetSignatures()) {
|
||||
return ctx, sdk.ErrUnauthorized("Number of signatures do not match required amount").Result(), true
|
||||
}
|
||||
|
||||
signBytes := msg.GetSignBytes()
|
||||
for i, addr := range signerAddrs {
|
||||
sig := appTx.GetSignatures()[i]
|
||||
|
||||
// check that submitted pubkey belongs to required address
|
||||
if !bytes.Equal(sig.PubKey.Address(), addr) {
|
||||
return ctx, sdk.ErrUnauthorized("Provided Pubkey does not match required address").Result(), true
|
||||
}
|
||||
|
||||
// check that signature is over expected signBytes
|
||||
if !sig.PubKey.VerifyBytes(signBytes, sig.Signature) {
|
||||
return ctx, sdk.ErrUnauthorized("Signature verification failed").Result(), true
|
||||
}
|
||||
}
|
||||
|
||||
// authentication passed, app to continue processing by sending msg to handler
|
||||
return ctx, sdk.Result{}, false
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
cmn "github.com/tendermint/tendermint/libs/common"
|
||||
dbm "github.com/tendermint/tendermint/libs/db"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
|
||||
bapp "github.com/cosmos/cosmos-sdk/baseapp"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
"github.com/cosmos/cosmos-sdk/x/bank"
|
||||
)
|
||||
|
||||
const (
|
||||
app3Name = "App3"
|
||||
)
|
||||
|
||||
func NewApp3(logger log.Logger, db dbm.DB) *bapp.BaseApp {
|
||||
|
||||
// Create the codec with registered Msg types
|
||||
cdc := NewCodec()
|
||||
|
||||
// Create the base application object.
|
||||
app := bapp.NewBaseAppNoCodec(app3Name, logger, db, auth.DefaultTxDecoder(cdc))
|
||||
|
||||
// Create a key for accessing the account store.
|
||||
keyAccount := sdk.NewKVStoreKey("acc")
|
||||
keyFees := sdk.NewKVStoreKey("fee") // TODO
|
||||
|
||||
// Set various mappers/keepers to interact easily with underlying stores
|
||||
accountMapper := auth.NewAccountMapper(cdc, keyAccount, auth.ProtoBaseAccount)
|
||||
coinKeeper := bank.NewKeeper(accountMapper)
|
||||
feeKeeper := auth.NewFeeCollectionKeeper(cdc, keyFees)
|
||||
|
||||
app.SetAnteHandler(auth.NewAnteHandler(accountMapper, feeKeeper))
|
||||
|
||||
// Register message routes.
|
||||
// Note the handler gets access to
|
||||
app.Router().
|
||||
AddRoute("send", bank.NewHandler(coinKeeper))
|
||||
|
||||
// Mount stores and load the latest state.
|
||||
app.MountStoresIAVL(keyAccount, keyFees)
|
||||
err := app.LoadLatestVersion(keyAccount)
|
||||
if err != nil {
|
||||
cmn.Exit(err.Error())
|
||||
}
|
||||
return app
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
cmn "github.com/tendermint/tendermint/libs/common"
|
||||
dbm "github.com/tendermint/tendermint/libs/db"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
|
||||
bapp "github.com/cosmos/cosmos-sdk/baseapp"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/wire"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
"github.com/cosmos/cosmos-sdk/x/bank"
|
||||
)
|
||||
|
||||
const (
|
||||
app4Name = "App4"
|
||||
)
|
||||
|
||||
func NewApp4(logger log.Logger, db dbm.DB) *bapp.BaseApp {
|
||||
|
||||
cdc := NewCodec()
|
||||
|
||||
// Create the base application object.
|
||||
app := bapp.NewBaseAppNoCodec(app4Name, logger, db, auth.DefaultTxDecoder(cdc))
|
||||
|
||||
// Create a key for accessing the account store.
|
||||
keyAccount := sdk.NewKVStoreKey("acc")
|
||||
|
||||
// Set various mappers/keepers to interact easily with underlying stores
|
||||
accountMapper := auth.NewAccountMapper(cdc, keyAccount, auth.ProtoBaseAccount)
|
||||
coinKeeper := bank.NewKeeper(accountMapper)
|
||||
|
||||
// TODO
|
||||
keyFees := sdk.NewKVStoreKey("fee")
|
||||
feeKeeper := auth.NewFeeCollectionKeeper(cdc, keyFees)
|
||||
|
||||
app.SetAnteHandler(auth.NewAnteHandler(accountMapper, feeKeeper))
|
||||
|
||||
// Set InitChainer
|
||||
app.SetInitChainer(NewInitChainer(cdc, accountMapper))
|
||||
|
||||
// Register message routes.
|
||||
// Note the handler gets access to the account store.
|
||||
app.Router().
|
||||
AddRoute("send", bank.NewHandler(coinKeeper))
|
||||
|
||||
// Mount stores and load the latest state.
|
||||
app.MountStoresIAVL(keyAccount, keyFees)
|
||||
err := app.LoadLatestVersion(keyAccount)
|
||||
if err != nil {
|
||||
cmn.Exit(err.Error())
|
||||
}
|
||||
return app
|
||||
}
|
||||
|
||||
// Application state at Genesis has accounts with starting balances
|
||||
type GenesisState struct {
|
||||
Accounts []*GenesisAccount `json:"accounts"`
|
||||
}
|
||||
|
||||
// GenesisAccount doesn't need pubkey or sequence
|
||||
type GenesisAccount struct {
|
||||
Address sdk.AccAddress `json:"address"`
|
||||
Coins sdk.Coins `json:"coins"`
|
||||
}
|
||||
|
||||
// Converts GenesisAccount to auth.BaseAccount for storage in account store
|
||||
func (ga *GenesisAccount) ToAccount() (acc *auth.BaseAccount, err error) {
|
||||
baseAcc := auth.BaseAccount{
|
||||
Address: ga.Address,
|
||||
Coins: ga.Coins.Sort(),
|
||||
}
|
||||
return &baseAcc, nil
|
||||
}
|
||||
|
||||
// InitChainer will set initial balances for accounts as well as initial coin metadata
|
||||
// MsgIssue can no longer be used to create new coin
|
||||
func NewInitChainer(cdc *wire.Codec, accountMapper auth.AccountMapper) sdk.InitChainer {
|
||||
return func(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain {
|
||||
stateJSON := req.AppStateBytes
|
||||
|
||||
genesisState := new(GenesisState)
|
||||
err := cdc.UnmarshalJSON(stateJSON, genesisState)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
for _, gacc := range genesisState.Accounts {
|
||||
acc, err := gacc.ToAccount()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
acc.AccountNumber = accountMapper.GetNextAccountNumber(ctx)
|
||||
accountMapper.SetAccount(ctx, acc)
|
||||
}
|
||||
|
||||
return abci.ResponseInitChain{}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user