mirror of
https://github.com/tendermint/tendermint.git
synced 2026-08-17 12:46:16 +00:00
wip
This commit is contained in:
@@ -132,6 +132,8 @@ func New(db dbm.DB) (*StateMachine, error) {
|
||||
lastHeight: int64(lastHeight),
|
||||
lastHash: lastHash,
|
||||
db: db,
|
||||
touchedAccounts: make(map[uint64]struct{}),
|
||||
newPairs: make([]*Pair, 0),
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -276,11 +278,15 @@ func (sm *StateMachine) PrepareProposal(req types.RequestPrepareProposal) types.
|
||||
continue
|
||||
}
|
||||
|
||||
fmt.Println("we have a tradeset")
|
||||
|
||||
tradeSet = sm.validateTradeSetAgainstState(tradeSet)
|
||||
if tradeSet == nil || len(tradeSet.MatchedOrders) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
fmt.Println("we have a valid tradeset")
|
||||
|
||||
// wrap this as a message typ
|
||||
msgTradeSet := &MsgTradeSet{TradeSet: tradeSet}
|
||||
bz, err := proto.Marshal(msgTradeSet)
|
||||
@@ -311,6 +317,7 @@ func (sm *StateMachine) ProcessProposal(req types.RequestProcessProposal) types.
|
||||
}
|
||||
|
||||
if status := sm.ValidateTx(msg); status != StatusOK {
|
||||
fmt.Printf("tx failed validation, status: %d\n", status)
|
||||
return rejectProposal()
|
||||
}
|
||||
}
|
||||
@@ -349,11 +356,11 @@ func (sm *StateMachine) DeliverTx(req types.RequestDeliverTx) types.ResponseDeli
|
||||
|
||||
case *Msg_MsgCreateAccount:
|
||||
nextAccountID := uint64(len(sm.accounts))
|
||||
sm.accounts[nextAccountID] = &Account{
|
||||
sm.accounts = append(sm.accounts, &Account{
|
||||
Index: nextAccountID,
|
||||
PublicKey: m.MsgCreateAccount.PublicKey,
|
||||
Commodities: m.MsgCreateAccount.Commodities,
|
||||
}
|
||||
})
|
||||
sm.touchedAccounts[nextAccountID] = struct{}{}
|
||||
sm.publicKeys[string(m.MsgCreateAccount.PublicKey)] = struct{}{}
|
||||
|
||||
@@ -452,7 +459,7 @@ func (sm *StateMachine) hash() []byte {
|
||||
func (sm *StateMachine) updateState(batch dbm.Batch, height int64, hash []byte) error {
|
||||
sm.lastHash = hash
|
||||
sm.lastHeight = height
|
||||
var heightBytes []byte
|
||||
heightBytes := make([]byte, 8)
|
||||
binary.BigEndian.PutUint64(heightBytes, uint64(height))
|
||||
return batch.Set(stateKey, append(heightBytes, hash...))
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package orderbook_test
|
||||
|
||||
import (
|
||||
"crypto/ed25519"
|
||||
fmt "fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/cosmos/gogoproto/proto"
|
||||
@@ -11,6 +11,8 @@ import (
|
||||
"github.com/tendermint/tendermint/abci/example/orderbook"
|
||||
"github.com/tendermint/tendermint/abci/types"
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
"github.com/tendermint/tendermint/crypto/ed25519"
|
||||
params "github.com/tendermint/tendermint/types"
|
||||
)
|
||||
|
||||
// TODO: we should also check that CheckTx adds bids and asks to the app-side mempool
|
||||
@@ -187,6 +189,117 @@ func TestCheckTx(t *testing.T) {
|
||||
// and from existing state
|
||||
// func TestNewStateMachine(t *testing.T) {}
|
||||
|
||||
func TestEndToEnd(t *testing.T) {
|
||||
db := dbm.NewMemDB()
|
||||
app, err := orderbook.New(db)
|
||||
require.NoError(t, err)
|
||||
|
||||
|
||||
var (
|
||||
maxBytes = params.DefaultConsensusParams().Block.MaxBytes
|
||||
commodityNZD = &orderbook.Commodity{Denom: "NZD", Quantity: 100}
|
||||
commodityAUD = &orderbook.Commodity{Denom: "AUD", Quantity: 100}
|
||||
registerPairMsg = newRegisterPair("NZD", "AUD")
|
||||
pair = registerPairMsg.GetMsgRegisterPair().Pair
|
||||
pkAlice = ed25519.GenPrivKey()
|
||||
pkBob = ed25519.GenPrivKey()
|
||||
pubKeyAlice = pkAlice.PubKey().Bytes()
|
||||
pubKeyBob = pkBob.PubKey().Bytes()
|
||||
registerAlice = newRegisterAccount(pubKeyAlice, []*orderbook.Commodity{commodityAUD})
|
||||
registerBob = newRegisterAccount(pubKeyBob, []*orderbook.Commodity{commodityNZD})
|
||||
// bob is asking for 25 AUD for 5 NZD
|
||||
ask = &orderbook.Msg{Sum: &orderbook.Msg_MsgAsk{MsgAsk: orderbook.NewMsgAsk(pair, 5, 5, 1)}}
|
||||
// alice is bidding for 5 NZD for 25 AUD
|
||||
bid = &orderbook.Msg{Sum: &orderbook.Msg_MsgBid{MsgBid: orderbook.NewMsgBid(pair, 5, 5, 0)}}
|
||||
)
|
||||
|
||||
require.NoError(t, ask.GetMsgAsk().Sign(pkBob))
|
||||
require.NoError(t, bid.GetMsgBid().Sign(pkAlice))
|
||||
|
||||
testCases := []struct {
|
||||
txs [][]byte
|
||||
accepted bool
|
||||
// assertions to be made about the state of the application
|
||||
// after each block
|
||||
assertions func(t *testing.T, app *orderbook.StateMachine)
|
||||
}{
|
||||
{
|
||||
// block 1 sets up the trading pair
|
||||
txs: asTxs(registerPairMsg),
|
||||
accepted: true,
|
||||
assertions: func(t *testing.T, app *orderbook.StateMachine) {
|
||||
pairs := app.Pairs()
|
||||
require.Len(t, pairs, 1)
|
||||
require.Equal(t, pair, &pairs[0])
|
||||
},
|
||||
},
|
||||
{
|
||||
// block 2 registers two accounts: alice and bob
|
||||
txs: asTxs(registerAlice, registerBob),
|
||||
accepted: true,
|
||||
assertions: func(t *testing.T, app *orderbook.StateMachine) {
|
||||
alice := app.Account(0)
|
||||
require.False(t, alice.IsEmpty(), alice)
|
||||
require.Equal(t, pubKeyAlice, alice.PublicKey)
|
||||
require.Len(t, alice.Commodities, 1)
|
||||
require.Equal(t, alice.Commodities[0], commodityAUD)
|
||||
bob := app.Account(1)
|
||||
require.False(t, bob.IsEmpty(), bob)
|
||||
require.Equal(t, pubKeyBob, bob.PublicKey)
|
||||
require.Len(t, bob.Commodities, 1)
|
||||
require.Equal(t, bob.Commodities[0], commodityNZD)
|
||||
require.True(t, app.Account(2).IsEmpty())
|
||||
},
|
||||
},
|
||||
{
|
||||
// block 3 performs a trade between alice and bob
|
||||
txs: asTxs(ask, bid),
|
||||
accepted: true,
|
||||
assertions: func(t *testing.T, app *orderbook.StateMachine) {
|
||||
alice := app.Account(0)
|
||||
require.Equal(t, alice.Commodities[0].Quantity, 75) // 75 AUD
|
||||
require.Equal(t, alice.Commodities[1].Quantity, 5) // 5 NZD
|
||||
bob := app.Account(1)
|
||||
require.Equal(t, bob.Commodities[0].Quantity, 95) // 95 NZD
|
||||
require.Equal(t, bob.Commodities[0].Quantity, 5) // 5 AUD
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for idx, tc := range testCases {
|
||||
for _, tx := range tc.txs {
|
||||
resp := app.CheckTx(types.RequestCheckTx{Tx: tx})
|
||||
require.EqualValues(t, orderbook.StatusOK, resp.Code)
|
||||
}
|
||||
txs := app.PrepareProposal(types.RequestPrepareProposal{MaxTxBytes: maxBytes, Txs: tc.txs}).Txs
|
||||
require.Equal(t, txs, tc.txs)
|
||||
if idx == 2 {
|
||||
fmt.Print(tc.txs)
|
||||
fmt.Println()
|
||||
fmt.Print(txs)
|
||||
}
|
||||
|
||||
result := app.ProcessProposal(types.RequestProcessProposal{Txs: txs})
|
||||
if tc.accepted {
|
||||
require.Equal(t, types.ResponseProcessProposal_ACCEPT, result.Status)
|
||||
} else {
|
||||
require.Equal(t, types.ResponseProcessProposal_REJECT, result.Status)
|
||||
continue
|
||||
}
|
||||
|
||||
app.BeginBlock(types.RequestBeginBlock{})
|
||||
for _, tx := range txs {
|
||||
app.DeliverTx(types.RequestDeliverTx{Tx: tx})
|
||||
}
|
||||
app.EndBlock(types.RequestEndBlock{})
|
||||
app.Commit()
|
||||
|
||||
if tc.assertions != nil {
|
||||
tc.assertions(t, app)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func asTxs(msgs ...*orderbook.Msg) [][]byte {
|
||||
output := make([][]byte, len(msgs))
|
||||
for i, msg := range msgs {
|
||||
@@ -205,65 +318,10 @@ func newRegisterPair(d1, d2 string) *orderbook.Msg {
|
||||
}}}
|
||||
}
|
||||
|
||||
func newRegisterAccount(pubkey []byte, commodities []*orderbook.Commodity ) *orderbook.Msg {
|
||||
func newRegisterAccount(pubkey []byte, commodities []*orderbook.Commodity) *orderbook.Msg {
|
||||
return &orderbook.Msg{Sum: &orderbook.Msg_MsgCreateAccount{MsgCreateAccount: &orderbook.MsgCreateAccount{
|
||||
PublicKey: pubkey,
|
||||
PublicKey: pubkey,
|
||||
Commodities: commodities,
|
||||
}}}
|
||||
}
|
||||
|
||||
func TestEndToEnd(t *testing.T) {
|
||||
db := dbm.NewMemDB()
|
||||
_, err := orderbook.New(db)
|
||||
require.NoError(t, err)
|
||||
|
||||
// registerPairMsg := newRegisterPair("NZD", "AUD")
|
||||
// registerAccountMsg := newRegisterAccount()
|
||||
|
||||
// app.ProcessProposal(types.RequestProcessProposal{Txs: asTxs(registerPairMsg, registerAccountMsg)})
|
||||
|
||||
// for _, tc := range testCases {
|
||||
// t.Run(tc.name, func(t *testing.T) {
|
||||
// bz, err := proto.Marshal(tc.msg)
|
||||
// require.NoError(t, err)
|
||||
// resp := app.DeliverTx(types.RequestDeliverTx{Tx: bz})
|
||||
// require.Equal(t, tc.responseCode, resp.Code, resp.Log)
|
||||
// })
|
||||
// }
|
||||
// name: "test create account",
|
||||
// msg: &orderbook.Msg{
|
||||
// Sum: &orderbook.Msg_MsgAsk{
|
||||
// MsgAsk: &orderbook.MsgAsk{
|
||||
// Pair: testPair,
|
||||
// AskOrder: &orderbook.OrderAsk{
|
||||
// Quantity: 10,
|
||||
// AskPrice: 1,
|
||||
// OwnerId: 1,
|
||||
// Signature: crypto.CRandBytes(ed25519.SignatureSize),
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// responseCode: orderbook.StatusOK,
|
||||
// expOrderSize: 1,
|
||||
// },
|
||||
// {
|
||||
// name: "test add tradeset",
|
||||
// msg: &orderbook.Msg{
|
||||
// Sum: &orderbook.Msg_MsgAsk{
|
||||
// MsgAsk: &orderbook.MsgAsk{
|
||||
// Pair: testPair,
|
||||
// AskOrder: &orderbook.OrderAsk{
|
||||
// Quantity: 10,
|
||||
// AskPrice: 1,
|
||||
// OwnerId: 1,
|
||||
// Signature: crypto.CRandBytes(ed25519.SignatureSize),
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// responseCode: orderbook.StatusOK,
|
||||
// expOrderSize: 1,
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
@@ -47,15 +47,20 @@ func NewCLI() *CLI {
|
||||
|
||||
viper.AddConfigPath(filepath.Join(root, "config"))
|
||||
viper.SetConfigName("config")
|
||||
|
||||
if err := viper.ReadInConfig(); err != nil {
|
||||
// return err
|
||||
}
|
||||
|
||||
|
||||
config := cfg.DefaultConfig()
|
||||
|
||||
if err := viper.Unmarshal(config); err != nil {
|
||||
return err
|
||||
if err := viper.ReadInConfig(); err != nil {
|
||||
if _, ok := err.(viper.ConfigFileNotFoundError); ok {
|
||||
// Config file not found; use default
|
||||
// This often happens when initializing a config for the first time
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := viper.Unmarshal(config); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
config.SetRoot(root)
|
||||
|
||||
@@ -167,8 +167,8 @@ func (o *OrderBid) DeterministicSignatureBytes(pair *Pair) []byte {
|
||||
buf.WriteString(pair.SellersDenomination)
|
||||
buf.WriteString(pair.BuyersDenomination)
|
||||
bz := buf.Bytes()
|
||||
binary.BigEndian.PutUint64(bz, math.Float64bits(o.MaxQuantity))
|
||||
binary.BigEndian.PutUint64(bz, math.Float64bits(o.MaxPrice))
|
||||
bz = binary.BigEndian.AppendUint64(bz, math.Float64bits(o.MaxQuantity))
|
||||
bz = binary.BigEndian.AppendUint64(bz, math.Float64bits(o.MaxPrice))
|
||||
return bz
|
||||
}
|
||||
|
||||
@@ -227,11 +227,15 @@ func (o *OrderAsk) DeterministicSignatureBytes(pair *Pair) []byte {
|
||||
buf.WriteString(pair.BuyersDenomination)
|
||||
buf.WriteString(pair.SellersDenomination)
|
||||
bz := buf.Bytes()
|
||||
binary.BigEndian.PutUint64(bz, math.Float64bits(o.Quantity))
|
||||
binary.BigEndian.PutUint64(bz, math.Float64bits(o.AskPrice))
|
||||
bz = binary.BigEndian.AppendUint64(bz, math.Float64bits(o.Quantity))
|
||||
bz = binary.BigEndian.AppendUint64(bz, math.Float64bits(o.AskPrice))
|
||||
return bz
|
||||
}
|
||||
|
||||
func (a Account) IsEmpty() bool {
|
||||
return len(a.PublicKey) == 0
|
||||
}
|
||||
|
||||
func (a *Account) FindCommidity(denom string) *Commodity {
|
||||
for _, c := range a.Commodities {
|
||||
if c.Denom == denom {
|
||||
|
||||
Reference in New Issue
Block a user