types/rational: use encoding/json

minor fixes

working on compiling
This commit is contained in:
Ethan Buchman 2018-03-16 20:52:39 +01:00 committed by rigelrozanski
parent 8e3f8319af
commit af6c1a3f02
8 changed files with 102 additions and 68 deletions

View File

@ -109,6 +109,10 @@ func ErrInvalidCoins(msg string) Error {
return newError(CodeInvalidCoins, msg) return newError(CodeInvalidCoins, msg)
} }
func ErrInvalidCoins(coins Coins) Error {
return newError(CodeInvalidCoins, coins.String())
}
//---------------------------------------- //----------------------------------------
// Error & sdkError // Error & sdkError

View File

@ -1,6 +1,9 @@
package types package types
import ( import (
"bytes"
"encoding/json"
"fmt"
"math/big" "math/big"
"strconv" "strconv"
"strings" "strings"
@ -13,12 +16,21 @@ import (
// __| |_ |_ // __| |_ |_
// Rat - extend big.Rat // Rat - extend big.Rat
// NOTE: never use new(Rat) or else
// we will panic unmarshalling into the
// nil embedded big.Rat
type Rat struct { type Rat struct {
*big.Rat `json:"rat"` *big.Rat `json:"rat"`
} }
// Rational - big Rat with additional functionality type Rational = Rat
type Rational interface {
// RationalInterface - big Rat with additional functionality
// NOTE: we only have one implementation of this interface
// and don't use it anywhere, but it might come in handy
// if we want to provide Rational types that include
// the units of the value in the type system.
type RationalInterface interface {
GetRat() *big.Rat GetRat() *big.Rat
Num() int64 Num() int64
Denom() int64 Denom() int64
@ -200,6 +212,37 @@ func (r Rat) Round(precisionFactor int64) Rational {
//return nil //return nil
//} //}
//nolint var ratCdc JSONCodec // TODO wire.Codec
func (r Rat) MarshalJSON() ([]byte, error) { return r.MarshalText() }
func (r *Rat) UnmarshalJSON(data []byte) (err error) { return r.UnmarshalText(data) } // Hack to just use json.Marshal for everything until
// we update for amino
type JSONCodec struct{}
func (jc JSONCodec) MarshalJSON(o interface{}) ([]byte, error) {
return json.Marshal(o)
}
func (jc JSONCodec) UnmarshalJSON(bz []byte, o interface{}) error {
return json.Unmarshal(bz, o)
}
// Wraps r.MarshalText() in quotes to make it a valid JSON string.
func (r Rat) MarshalJSON() ([]byte, error) {
bz, err := r.MarshalText()
if err != nil {
return bz, err
}
return []byte(fmt.Sprintf(`"%s"`, bz)), nil
}
// Requires a valid JSON string - strings quotes and calls UnmarshalText
func (r *Rat) UnmarshalJSON(data []byte) (err error) {
quote := []byte(`"`)
if len(data) < 2 ||
!bytes.HasPrefix(data, quote) ||
!bytes.HasSuffix(data, quote) {
return fmt.Errorf("JSON encoded Rat must be a quote-delimitted string")
}
data = bytes.Trim(data, `"`)
return r.UnmarshalText(data)
}

View File

@ -1,7 +1,6 @@
package types package types
import ( import (
"encoding/json"
"math/big" "math/big"
"testing" "testing"
@ -193,41 +192,44 @@ func TestRound(t *testing.T) {
} }
func TestZeroSerializationJSON(t *testing.T) { func TestZeroSerializationJSON(t *testing.T) {
var r Rat r := NewRat(0, 1)
err := json.Unmarshal([]byte("{\"numerator\":0,\"denominator\":1}"), &r) err := r.UnmarshalJSON([]byte(`"0/1"`))
assert.Nil(t, err) assert.Nil(t, err)
err = json.Unmarshal([]byte("{\"numerator\":0,\"denominator\":0}"), &r) err = r.UnmarshalJSON([]byte(`"0/0"`))
assert.NotNil(t, err) assert.NotNil(t, err)
err = json.Unmarshal([]byte("{\"numerator\":1,\"denominator\":0}"), &r) err = r.UnmarshalJSON([]byte(`"1/0"`))
assert.NotNil(t, err) assert.NotNil(t, err)
err = json.Unmarshal([]byte("{}"), &r) err = r.UnmarshalJSON([]byte(`"{}"`))
assert.NotNil(t, err) assert.NotNil(t, err)
} }
func TestSerializationJSON(t *testing.T) { func TestSerializationJSON(t *testing.T) {
r := NewRat(1, 3) r := NewRat(1, 3)
rMarshal, err := json.Marshal(r) bz, err := r.MarshalText()
require.Nil(t, err) require.Nil(t, err)
var rUnmarshal Rat r2 := NewRat(0, 1)
err = json.Unmarshal(rMarshal, &rUnmarshal) err = r2.UnmarshalText(bz)
require.Nil(t, err) require.Nil(t, err)
assert.True(t, r.Equal(rUnmarshal), "original: %v, unmarshalled: %v", r, rUnmarshal) assert.True(t, r.Equal(r2), "original: %v, unmarshalled: %v", r, r2)
} }
func TestSerializationGoWire(t *testing.T) { func TestSerializationGoWire(t *testing.T) {
r := NewRat(1, 3) r := NewRat(1, 3)
rMarshal, err := ratCdc.MarshalJSON(r) bz, err := ratCdc.MarshalJSON(r)
require.Nil(t, err) require.Nil(t, err)
var rUnmarshal Rat bz, err = r.MarshalJSON()
err = ratCdc.UnmarshalJSON(rMarshal, &rUnmarshal)
require.Nil(t, err) require.Nil(t, err)
assert.True(t, r.Equal(rUnmarshal), "original: %v, unmarshalled: %v", r, rUnmarshal) r2 := NewRat(0, 1)
err = ratCdc.UnmarshalJSON(bz, &r2)
require.Nil(t, err)
assert.True(t, r.Equal(r2), "original: %v, unmarshalled: %v", r, r2)
} }
type testEmbedStruct struct { type testEmbedStruct struct {
@ -237,38 +239,18 @@ type testEmbedStruct struct {
} }
func TestEmbeddedStructSerializationGoWire(t *testing.T) { func TestEmbeddedStructSerializationGoWire(t *testing.T) {
r := testEmbedStruct{"foo", 10, NewRat(1, 3)} obj := testEmbedStruct{"foo", 10, NewRat(1, 3)}
rMarshal, err := ratCdc.MarshalJSON(r) bz, err := ratCdc.MarshalJSON(obj)
require.Nil(t, err) require.Nil(t, err)
var rUnmarshal testEmbedStruct var obj2 testEmbedStruct
err = ratCdc.UnmarshalJSON(rMarshal, &rUnmarshal) obj2.Field3 = NewRat(0, 1) // ... needs to be initialized
err = ratCdc.UnmarshalJSON(bz, &obj2)
require.Nil(t, err) require.Nil(t, err)
assert.Equal(t, r.Field1, rUnmarshal.Field1) assert.Equal(t, obj.Field1, obj2.Field1)
assert.Equal(t, r.Field2, rUnmarshal.Field2) assert.Equal(t, obj.Field2, obj2.Field2)
assert.True(t, r.Field3.Equal(rUnmarshal.Field3), "original: %v, unmarshalled: %v", r, rUnmarshal) assert.True(t, obj.Field3.Equal(obj2.Field3), "original: %v, unmarshalled: %v", obj, obj2)
} }
type testEmbedInterface struct {
Field1 string `json:"f1"`
Field2 int `json:"f2"`
Field3 Rational `json:"f3"`
}
func TestEmbeddedInterfaceSerializationGoWire(t *testing.T) {
r := testEmbedInterface{"foo", 10, NewRat(1, 3)}
rMarshal, err := ratCdc.MarshalJSON(r)
require.Nil(t, err)
var rUnmarshal testEmbedInterface
err = ratCdc.UnmarshalJSON(rMarshal, &rUnmarshal)
require.Nil(t, err)
assert.Equal(t, r.Field1, rUnmarshal.Field1)
assert.Equal(t, r.Field2, rUnmarshal.Field2)
assert.True(t, r.Field3.Equal(rUnmarshal.Field3), "original: %v, unmarshalled: %v", r, rUnmarshal)
}

View File

@ -301,7 +301,7 @@ func (m Mapper) removeDelegatorBond(delegator sdk.Address, candidateAddr sdk.Add
addrs = append(addrs[:i], addrs[i+1:]...) addrs = append(addrs[:i], addrs[i+1:]...)
} }
} }
b, err := m.cdc.MarshalJSON(pks) b, err := m.cdc.MarshalJSON(addrs)
if err != nil { if err != nil {
panic(err) panic(err)
} }

View File

@ -11,6 +11,7 @@ import (
crypto "github.com/tendermint/go-crypto" crypto "github.com/tendermint/go-crypto"
dbm "github.com/tendermint/tmlibs/db" dbm "github.com/tendermint/tmlibs/db"
"github.com/cosmos/cosmos-sdk/store"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
) )
@ -21,18 +22,18 @@ func subspace(prefix []byte) (start, end []byte) {
return prefix, end return prefix, end
} }
func createTestInput(t *testing.T, isCheckTx bool) (store sdk.KVStore, ctx sdk.Context, key sdk.StoreKey) { func createTestInput(t *testing.T, isCheckTx bool) (sdk.KVStore, sdk.Context, sdk.StoreKey) {
db := dbm.NewMemDB() db := dbm.NewMemDB()
key = sdk.NewKVStoreKey("stake") key := sdk.NewKVStoreKey("stake")
ms := store.NewCommitMultiStore(db) ms := store.NewCommitMultiStore(db)
ms.MountStoreWithDB(key, sdk.StoreTypeIAVL, db) ms.MountStoreWithDB(key, sdk.StoreTypeIAVL, db)
err := ms.LoadLatestVersion() err := ms.LoadLatestVersion()
require.Nil(t, err) require.Nil(t, err)
ctx = sdk.NewContext(ms, abci.Header{ChainID: "foochainid"}, isCheckTx, nil) ctx := sdk.NewContext(ms, abci.Header{ChainID: "foochainid"}, isCheckTx, nil)
store = ms.GetKVStore(key) store := ms.GetKVStore(key)
return return store, ctx, key
} }
func newAddrs(n int) (addrs []crypto.Address) { func newAddrs(n int) (addrs []crypto.Address) {
@ -50,7 +51,7 @@ func newPubKey(pk string) (res crypto.PubKey) {
//res, err = crypto.PubKeyFromBytes(pkBytes) //res, err = crypto.PubKeyFromBytes(pkBytes)
var pkEd crypto.PubKeyEd25519 var pkEd crypto.PubKeyEd25519
copy(pkEd[:], pkBytes[:]) copy(pkEd[:], pkBytes[:])
return pkEd return pkEd.Wrap()
} }
// dummy pubkeys used for testing // dummy pubkeys used for testing
@ -74,7 +75,7 @@ func candidatesFromActors(store sdk.KVStore, addrs []crypto.Address, amts []int6
c := &Candidate{ c := &Candidate{
Status: Unbonded, Status: Unbonded,
PubKey: pks[i], PubKey: pks[i],
Owner: addrs[i], Address: addrs[i],
Assets: sdk.NewRat(amts[i]), Assets: sdk.NewRat(amts[i]),
Liabilities: sdk.NewRat(amts[i]), Liabilities: sdk.NewRat(amts[i]),
VotingPower: sdk.NewRat(amts[i]), VotingPower: sdk.NewRat(amts[i]),
@ -83,12 +84,14 @@ func candidatesFromActors(store sdk.KVStore, addrs []crypto.Address, amts []int6
} }
} }
func saveCandidate(store sdk.KVStore, c *Candidate) {} // TODO
func candidatesFromActorsEmpty(addrs []crypto.Address) (candidates Candidates) { func candidatesFromActorsEmpty(addrs []crypto.Address) (candidates Candidates) {
for i := 0; i < len(addrs); i++ { for i := 0; i < len(addrs); i++ {
c := &Candidate{ c := &Candidate{
Status: Unbonded, Status: Unbonded,
PubKey: pks[i], PubKey: pks[i],
Owner: addrs[i], Address: addrs[i],
Assets: sdk.ZeroRat, Assets: sdk.ZeroRat,
Liabilities: sdk.ZeroRat, Liabilities: sdk.ZeroRat,
VotingPower: sdk.ZeroRat, VotingPower: sdk.ZeroRat,

View File

@ -22,6 +22,7 @@ func Tick(ctx sdk.Context, m Mapper) (change []*abci.Validator, err error) {
newVals := m.getValidators(params.MaxVals) newVals := m.getValidators(params.MaxVals)
// XXX determine change from old validators, set to change // XXX determine change from old validators, set to change
_ = newVals
return change, nil return change, nil
} }

View File

@ -167,10 +167,10 @@ type MsgUnbond struct {
Shares string `json:"shares"` Shares string `json:"shares"`
} }
func NewMsgUnbond(shares string, address sdk.Address) MsgDelegate { func NewMsgUnbond(bond sdk.Coin, address sdk.Address) MsgDelegate {
return MsgDelegate{ return MsgDelegate{
MsgAddr: NewMsgAddr(address), MsgAddr: NewMsgAddr(address),
Shares: shares, Bond: bond, // Shares: shares,
} }
} }
@ -202,10 +202,10 @@ func (msg MsgUnbond) ValidateBasic() sdk.Error {
func validateCoin(coin sdk.Coin) sdk.Error { func validateCoin(coin sdk.Coin) sdk.Error {
coins := sdk.Coins{coin} coins := sdk.Coins{coin}
if !coins.IsValid() { if !coins.IsValid() {
return sdk.ErrInvalidCoins() return sdk.ErrInvalidCoins(coins)
} }
if !coins.IsPositive() { if !coins.IsPositive() {
return fmt.Errorf("Amount must be > 0") return sdk.ErrInvalidCoins(coins) // XXX: add "Amount must be > 0" ?
} }
return nil return nil
} }

View File

@ -2,7 +2,6 @@ package stake
import ( import (
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
abci "github.com/tendermint/abci/types"
crypto "github.com/tendermint/go-crypto" crypto "github.com/tendermint/go-crypto"
) )
@ -167,7 +166,7 @@ type Description struct {
func NewCandidate(pubKey crypto.PubKey, address sdk.Address, description Description) *Candidate { func NewCandidate(pubKey crypto.PubKey, address sdk.Address, description Description) *Candidate {
return &Candidate{ return &Candidate{
Status: Unbonded, Status: Unbonded,
PubKey: pubKet, PubKey: pubKey,
Address: address, Address: address,
Assets: sdk.ZeroRat, Assets: sdk.ZeroRat,
Liabilities: sdk.ZeroRat, Liabilities: sdk.ZeroRat,
@ -222,7 +221,7 @@ func (c *Candidate) removeShares(shares sdk.Rat, gs *GlobalState) (createdCoins
// Should only be called when the Candidate qualifies as a validator. // Should only be called when the Candidate qualifies as a validator.
func (c *Candidate) validator() Validator { func (c *Candidate) validator() Validator {
return Validator{ return Validator{
PubKey: c.PubKey, Address: c.Address, // XXX !!!
VotingPower: c.VotingPower, VotingPower: c.VotingPower,
} }
} }
@ -234,8 +233,9 @@ type Validator struct {
} }
// ABCIValidator - Get the validator from a bond value // ABCIValidator - Get the validator from a bond value
/* TODO
func (v Validator) ABCIValidator() (*abci.Validator, error) { func (v Validator) ABCIValidator() (*abci.Validator, error) {
pkBytes, err := cdc.MarshalBinary(v.PubKey) pkBytes, err := wire.MarshalBinary(v.PubKey)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -244,6 +244,7 @@ func (v Validator) ABCIValidator() (*abci.Validator, error) {
Power: v.VotingPower.Evaluate(), Power: v.VotingPower.Evaluate(),
}, nil }, nil
} }
*/
//_________________________________________________________________________ //_________________________________________________________________________
@ -263,11 +264,11 @@ type DelegatorBond struct {
// Perform all the actions required to bond tokens to a delegator bond from their account // Perform all the actions required to bond tokens to a delegator bond from their account
func (bond *DelegatorBond) BondCoins(candidate *Candidate, tokens sdk.Coin, tr transact) sdk.Error { func (bond *DelegatorBond) BondCoins(candidate *Candidate, tokens sdk.Coin, tr transact) sdk.Error {
_, err := tr.coinKeeper.SubtractCoins(tr.ctx, d.Address, sdk.Coins{tokens}) _, err := tr.coinKeeper.SubtractCoins(tr.ctx, candidate.Address, sdk.Coins{tokens})
if err != nil { if err != nil {
return err return err
} }
newShares = candidate.addTokens(tokens.Amount, tr.gs) newShares := candidate.addTokens(tokens.Amount, tr.gs)
bond.Shares = bond.Shares.Add(newShares) bond.Shares = bond.Shares.Add(newShares)
return nil return nil
} }
@ -277,14 +278,14 @@ func (bond *DelegatorBond) UnbondCoins(candidate *Candidate, shares int64, tr tr
// subtract bond tokens from delegator bond // subtract bond tokens from delegator bond
if bond.Shares.LT(shares) { if bond.Shares.LT(shares) {
return ErrInsufficientFunds() return sdk.ErrInsufficientFunds("") // TODO
} }
bond.Shares = bond.Shares.Sub(shares) bond.Shares = bond.Shares.Sub(shares)
returnAmount := candidate.removeShares(shares, tr.gs) returnAmount := candidate.removeShares(shares, tr.gs)
returnCoins := sdk.Coins{{tr.params.BondDenom, returnAmount}} returnCoins := sdk.Coins{{tr.params.BondDenom, returnAmount}}
_, err := tr.coinKeeper.AddCoins(tr.ctx, d.Address, returnCoins) _, err := tr.coinKeeper.AddCoins(tr.ctx, candidate.Address, returnCoins)
if err != nil { if err != nil {
return err return err
} }