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)
}
func ErrInvalidCoins(coins Coins) Error {
return newError(CodeInvalidCoins, coins.String())
}
//----------------------------------------
// Error & sdkError

View File

@ -1,6 +1,9 @@
package types
import (
"bytes"
"encoding/json"
"fmt"
"math/big"
"strconv"
"strings"
@ -13,12 +16,21 @@ import (
// __| |_ |_
// Rat - extend big.Rat
// NOTE: never use new(Rat) or else
// we will panic unmarshalling into the
// nil embedded big.Rat
type Rat struct {
*big.Rat `json:"rat"`
}
// Rational - big Rat with additional functionality
type Rational interface {
type Rational = Rat
// 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
Num() int64
Denom() int64
@ -200,6 +212,37 @@ func (r Rat) Round(precisionFactor int64) Rational {
//return nil
//}
//nolint
func (r Rat) MarshalJSON() ([]byte, error) { return r.MarshalText() }
func (r *Rat) UnmarshalJSON(data []byte) (err error) { return r.UnmarshalText(data) }
var ratCdc JSONCodec // TODO wire.Codec
// 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
import (
"encoding/json"
"math/big"
"testing"
@ -193,41 +192,44 @@ func TestRound(t *testing.T) {
}
func TestZeroSerializationJSON(t *testing.T) {
var r Rat
err := json.Unmarshal([]byte("{\"numerator\":0,\"denominator\":1}"), &r)
r := NewRat(0, 1)
err := r.UnmarshalJSON([]byte(`"0/1"`))
assert.Nil(t, err)
err = json.Unmarshal([]byte("{\"numerator\":0,\"denominator\":0}"), &r)
err = r.UnmarshalJSON([]byte(`"0/0"`))
assert.NotNil(t, err)
err = json.Unmarshal([]byte("{\"numerator\":1,\"denominator\":0}"), &r)
err = r.UnmarshalJSON([]byte(`"1/0"`))
assert.NotNil(t, err)
err = json.Unmarshal([]byte("{}"), &r)
err = r.UnmarshalJSON([]byte(`"{}"`))
assert.NotNil(t, err)
}
func TestSerializationJSON(t *testing.T) {
r := NewRat(1, 3)
rMarshal, err := json.Marshal(r)
bz, err := r.MarshalText()
require.Nil(t, err)
var rUnmarshal Rat
err = json.Unmarshal(rMarshal, &rUnmarshal)
r2 := NewRat(0, 1)
err = r2.UnmarshalText(bz)
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) {
r := NewRat(1, 3)
rMarshal, err := ratCdc.MarshalJSON(r)
bz, err := ratCdc.MarshalJSON(r)
require.Nil(t, err)
var rUnmarshal Rat
err = ratCdc.UnmarshalJSON(rMarshal, &rUnmarshal)
bz, err = r.MarshalJSON()
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 {
@ -237,38 +239,18 @@ type testEmbedStruct struct {
}
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)
var rUnmarshal testEmbedStruct
err = ratCdc.UnmarshalJSON(rMarshal, &rUnmarshal)
var obj2 testEmbedStruct
obj2.Field3 = NewRat(0, 1) // ... needs to be initialized
err = ratCdc.UnmarshalJSON(bz, &obj2)
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)
assert.Equal(t, obj.Field1, obj2.Field1)
assert.Equal(t, obj.Field2, obj2.Field2)
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:]...)
}
}
b, err := m.cdc.MarshalJSON(pks)
b, err := m.cdc.MarshalJSON(addrs)
if err != nil {
panic(err)
}

View File

@ -11,6 +11,7 @@ import (
crypto "github.com/tendermint/go-crypto"
dbm "github.com/tendermint/tmlibs/db"
"github.com/cosmos/cosmos-sdk/store"
sdk "github.com/cosmos/cosmos-sdk/types"
)
@ -21,18 +22,18 @@ func subspace(prefix []byte) (start, end []byte) {
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()
key = sdk.NewKVStoreKey("stake")
key := sdk.NewKVStoreKey("stake")
ms := store.NewCommitMultiStore(db)
ms.MountStoreWithDB(key, sdk.StoreTypeIAVL, db)
err := ms.LoadLatestVersion()
require.Nil(t, err)
ctx = sdk.NewContext(ms, abci.Header{ChainID: "foochainid"}, isCheckTx, nil)
store = ms.GetKVStore(key)
return
ctx := sdk.NewContext(ms, abci.Header{ChainID: "foochainid"}, isCheckTx, nil)
store := ms.GetKVStore(key)
return store, ctx, key
}
func newAddrs(n int) (addrs []crypto.Address) {
@ -50,7 +51,7 @@ func newPubKey(pk string) (res crypto.PubKey) {
//res, err = crypto.PubKeyFromBytes(pkBytes)
var pkEd crypto.PubKeyEd25519
copy(pkEd[:], pkBytes[:])
return pkEd
return pkEd.Wrap()
}
// dummy pubkeys used for testing
@ -74,7 +75,7 @@ func candidatesFromActors(store sdk.KVStore, addrs []crypto.Address, amts []int6
c := &Candidate{
Status: Unbonded,
PubKey: pks[i],
Owner: addrs[i],
Address: addrs[i],
Assets: sdk.NewRat(amts[i]),
Liabilities: 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) {
for i := 0; i < len(addrs); i++ {
c := &Candidate{
Status: Unbonded,
PubKey: pks[i],
Owner: addrs[i],
Address: addrs[i],
Assets: sdk.ZeroRat,
Liabilities: 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)
// XXX determine change from old validators, set to change
_ = newVals
return change, nil
}

View File

@ -167,10 +167,10 @@ type MsgUnbond struct {
Shares string `json:"shares"`
}
func NewMsgUnbond(shares string, address sdk.Address) MsgDelegate {
func NewMsgUnbond(bond sdk.Coin, address sdk.Address) MsgDelegate {
return MsgDelegate{
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 {
coins := sdk.Coins{coin}
if !coins.IsValid() {
return sdk.ErrInvalidCoins()
return sdk.ErrInvalidCoins(coins)
}
if !coins.IsPositive() {
return fmt.Errorf("Amount must be > 0")
return sdk.ErrInvalidCoins(coins) // XXX: add "Amount must be > 0" ?
}
return nil
}

View File

@ -2,7 +2,6 @@ package stake
import (
sdk "github.com/cosmos/cosmos-sdk/types"
abci "github.com/tendermint/abci/types"
crypto "github.com/tendermint/go-crypto"
)
@ -167,7 +166,7 @@ type Description struct {
func NewCandidate(pubKey crypto.PubKey, address sdk.Address, description Description) *Candidate {
return &Candidate{
Status: Unbonded,
PubKey: pubKet,
PubKey: pubKey,
Address: address,
Assets: 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.
func (c *Candidate) validator() Validator {
return Validator{
PubKey: c.PubKey,
Address: c.Address, // XXX !!!
VotingPower: c.VotingPower,
}
}
@ -234,8 +233,9 @@ type Validator struct {
}
// ABCIValidator - Get the validator from a bond value
/* TODO
func (v Validator) ABCIValidator() (*abci.Validator, error) {
pkBytes, err := cdc.MarshalBinary(v.PubKey)
pkBytes, err := wire.MarshalBinary(v.PubKey)
if err != nil {
return nil, err
}
@ -244,6 +244,7 @@ func (v Validator) ABCIValidator() (*abci.Validator, error) {
Power: v.VotingPower.Evaluate(),
}, nil
}
*/
//_________________________________________________________________________
@ -263,11 +264,11 @@ type DelegatorBond struct {
// 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 {
_, 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 {
return err
}
newShares = candidate.addTokens(tokens.Amount, tr.gs)
newShares := candidate.addTokens(tokens.Amount, tr.gs)
bond.Shares = bond.Shares.Add(newShares)
return nil
}
@ -277,14 +278,14 @@ func (bond *DelegatorBond) UnbondCoins(candidate *Candidate, shares int64, tr tr
// subtract bond tokens from delegator bond
if bond.Shares.LT(shares) {
return ErrInsufficientFunds()
return sdk.ErrInsufficientFunds("") // TODO
}
bond.Shares = bond.Shares.Sub(shares)
returnAmount := candidate.removeShares(shares, tr.gs)
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 {
return err
}