mirror of
https://github.com/tendermint/tendermint.git
synced 2026-02-07 20:40:44 +00:00
wip
This commit is contained in:
@@ -26,11 +26,12 @@ func TestCheckTx(t *testing.T) {
|
||||
responseCode uint32
|
||||
expOrderSize int
|
||||
}{
|
||||
// {
|
||||
// name: "test empty tx",
|
||||
// msg: &orderbook.Msg{},
|
||||
// responseCode: orderbook.StatusErrUnknownMessage,
|
||||
// },
|
||||
{
|
||||
name: "test empty tx",
|
||||
msg: &orderbook.Msg{},
|
||||
responseCode: orderbook.StatusErrValidateBasic,
|
||||
expOrderSize: 0,
|
||||
},
|
||||
{
|
||||
name: "test msg ask",
|
||||
msg: &orderbook.Msg{
|
||||
@@ -49,26 +50,60 @@ func TestCheckTx(t *testing.T) {
|
||||
responseCode: orderbook.StatusOK,
|
||||
expOrderSize: 1,
|
||||
},
|
||||
// {
|
||||
// name: "test msg bid",
|
||||
// msg: &orderbook.Msg{Sum: &orderbook.Msg_MsgBid{MsgBid: &orderbook.MsgBid{
|
||||
// Pair: testPair,
|
||||
// BidOrder: &orderbook.OrderBid{
|
||||
// MaxQuantity: 15,
|
||||
// MaxPrice: 5,
|
||||
// OwnerId: 1,
|
||||
// Signature: []byte("signature"),
|
||||
// },
|
||||
// }}},
|
||||
// responseCode: orderbook.StatusOK,
|
||||
// },
|
||||
// {
|
||||
// name: "test msg register pair",
|
||||
// msg: &orderbook.Msg{Sum: &orderbook.Msg_MsgRegisterPair{MsgRegisterPair: &orderbook.MsgRegisterPair{
|
||||
// Pair: testPair,
|
||||
// }}},
|
||||
// responseCode: orderbook.StatusOK,
|
||||
// },
|
||||
{
|
||||
name: "test msg ask wrong signature",
|
||||
msg: &orderbook.Msg{
|
||||
Sum: &orderbook.Msg_MsgAsk{
|
||||
MsgAsk: &orderbook.MsgAsk{
|
||||
Pair: testPair,
|
||||
AskOrder: &orderbook.OrderAsk{
|
||||
Quantity: 10,
|
||||
AskPrice: 1,
|
||||
OwnerId: 1,
|
||||
Signature: crypto.CRandBytes(62),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
responseCode: orderbook.StatusErrValidateBasic,
|
||||
expOrderSize: 1,
|
||||
},
|
||||
{
|
||||
name: "test msg bid",
|
||||
msg: &orderbook.Msg{Sum: &orderbook.Msg_MsgBid{MsgBid: &orderbook.MsgBid{
|
||||
Pair: testPair,
|
||||
BidOrder: &orderbook.OrderBid{
|
||||
MaxQuantity: 15,
|
||||
MaxPrice: 5,
|
||||
OwnerId: 1,
|
||||
Signature: crypto.CRandBytes(ed25519.SignatureSize),
|
||||
},
|
||||
}}},
|
||||
responseCode: orderbook.StatusOK,
|
||||
expOrderSize: 2,
|
||||
},
|
||||
{
|
||||
name: "test msg bid blank",
|
||||
msg: &orderbook.Msg{Sum: &orderbook.Msg_MsgBid{MsgBid: &orderbook.MsgBid{
|
||||
Pair: testPair,
|
||||
BidOrder: &orderbook.OrderBid{
|
||||
MaxQuantity: 0,
|
||||
MaxPrice: 0,
|
||||
OwnerId: 0,
|
||||
Signature: crypto.CRandBytes(ed25519.SignatureSize),
|
||||
},
|
||||
}}},
|
||||
responseCode: orderbook.StatusErrValidateBasic,
|
||||
expOrderSize: 2,
|
||||
},
|
||||
{
|
||||
name: "test msg register duplicate pair",
|
||||
msg: &orderbook.Msg{Sum: &orderbook.Msg_MsgRegisterPair{MsgRegisterPair: &orderbook.MsgRegisterPair{
|
||||
Pair: &orderbook.Pair{BuyersDenomination: "ATOM", SellersDenomination: "ATOM"},
|
||||
}}},
|
||||
responseCode: orderbook.StatusErrValidateBasic,
|
||||
expOrderSize: 2,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
@@ -78,20 +113,62 @@ func TestCheckTx(t *testing.T) {
|
||||
resp := app.CheckTx(types.RequestCheckTx{Tx: bz})
|
||||
require.Equal(t, tc.responseCode, resp.Code, resp.Log)
|
||||
bids, asks := app.Orders(testPair)
|
||||
require.Equal(t, tc.expOrderSize, len(bids) + len(asks))
|
||||
require.Equal(t, tc.expOrderSize, len(bids)+len(asks))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: we should check that transactions in
|
||||
// a market are being validated and added to the proposal
|
||||
// and that other transactions get in
|
||||
// func TestPrepareProposal(t *testing.T) {
|
||||
// app := orderbook.New(dbm.NewMemDB())
|
||||
// func ValidateTx(t *testing.T) {
|
||||
// db := dbm.NewMemDB()
|
||||
// require.NoError(t, orderbook.InitDB(db, []*orderbook.Pair{testPair}, nil))
|
||||
// app, err := orderbook.New(db)
|
||||
// require.NoError(t, err)
|
||||
|
||||
// for _, tc := range testCases {
|
||||
// t.Run(tc.name, func(t *testing.T) {
|
||||
// bz, err := proto.Marshal(tc.msg)
|
||||
// require.NoError(t, err)
|
||||
// resp := app.CheckTx(types.RequestCheckTx{Tx: bz})
|
||||
// require.Equal(t, tc.responseCode, resp.Code, resp.Log)
|
||||
// bids, asks := app.Orders(testPair)
|
||||
// require.Equal(t, tc.expOrderSize, len(bids)+len(asks))
|
||||
// })
|
||||
// }
|
||||
// }
|
||||
|
||||
// TODO: we should check that transactions in
|
||||
// a market are being validated and added to the proposal
|
||||
// // and that other transactions get in
|
||||
// func TestPrepareProposal(t *testing.T) {
|
||||
// db := dbm.NewMemDB()
|
||||
// require.NoError(t, orderbook.InitDB(db, []*orderbook.Pair{testPair}, nil))
|
||||
// app, err := orderbook.New(db)
|
||||
// require.NoError(t, err)
|
||||
|
||||
// for _, tc := range testCases {
|
||||
// t.Run(tc.name, func(t *testing.T) {
|
||||
// bz, err := proto.Marshal(tc.msg)
|
||||
// require.NoError(t, err)
|
||||
// resp := app.CheckTx(types.RequestCheckTx{Tx: bz})
|
||||
// require.Equal(t, tc.responseCode, resp.Code, resp.Log)
|
||||
// bids, asks := app.Orders(testPair)
|
||||
// require.Equal(t, tc.expOrderSize, len(bids)+len(asks))
|
||||
// })
|
||||
// }
|
||||
// }
|
||||
|
||||
// {
|
||||
// name: "test msg register pair",
|
||||
// msg: &orderbook.Msg{Sum: &orderbook.Msg_MsgRegisterPair{MsgRegisterPair: &orderbook.MsgRegisterPair{
|
||||
// Pair: &orderbook.Pair{BuyersDenomination: "ATOM", SellersDenomination: "AUD"},
|
||||
// }}},
|
||||
// responseCode: orderbook.StatusOK,
|
||||
// expOrderSize: 2,
|
||||
// pairSize: 2,
|
||||
// },
|
||||
|
||||
// TODO: we should test that transactions are
|
||||
// always valid i.e. ValidateTx. We could potentially
|
||||
// always valid i.e. ValidateTx. We could potentially
|
||||
// combine this with PrepareProposal
|
||||
// func TestProcessProposal(t *testing.T) {
|
||||
// app := orderbook.New(dbm.NewMemDB())
|
||||
@@ -109,3 +186,84 @@ func TestCheckTx(t *testing.T) {
|
||||
// TODO: test that we can start from new
|
||||
// and from existing state
|
||||
// func TestNewStateMachine(t *testing.T) {}
|
||||
|
||||
func asTxs(msgs ...*orderbook.Msg) [][]byte {
|
||||
output := make([][]byte, len(msgs))
|
||||
for i, msg := range msgs {
|
||||
bz, err := proto.Marshal(msg)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
output[i] = bz
|
||||
}
|
||||
return output
|
||||
}
|
||||
|
||||
func newRegisterPair(d1, d2 string) *orderbook.Msg {
|
||||
return &orderbook.Msg{Sum: &orderbook.Msg_MsgRegisterPair{MsgRegisterPair: &orderbook.MsgRegisterPair{
|
||||
Pair: &orderbook.Pair{BuyersDenomination: d1, SellersDenomination: d2},
|
||||
}}}
|
||||
}
|
||||
|
||||
func newRegisterAccount(pubkey []byte, commodities []*orderbook.Commodity ) *orderbook.Msg {
|
||||
return &orderbook.Msg{Sum: &orderbook.Msg_MsgCreateAccount{MsgCreateAccount: &orderbook.MsgCreateAccount{
|
||||
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,
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
238
abci/example/orderbook/cmd/orderbook.go
Normal file
238
abci/example/orderbook/cmd/orderbook.go
Normal file
@@ -0,0 +1,238 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
|
||||
"github.com/tendermint/tendermint/abci/example/orderbook"
|
||||
cfg "github.com/tendermint/tendermint/config"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
tmos "github.com/tendermint/tendermint/libs/os"
|
||||
tmrand "github.com/tendermint/tendermint/libs/rand"
|
||||
"github.com/tendermint/tendermint/node"
|
||||
"github.com/tendermint/tendermint/p2p"
|
||||
"github.com/tendermint/tendermint/privval"
|
||||
"github.com/tendermint/tendermint/proxy"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
tmtime "github.com/tendermint/tendermint/types/time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
NewCLI().Run()
|
||||
}
|
||||
|
||||
type CLI struct {
|
||||
root *cobra.Command
|
||||
config *cfg.Config
|
||||
}
|
||||
|
||||
func NewCLI() *CLI {
|
||||
cli := &CLI{}
|
||||
cli.root = &cobra.Command{
|
||||
Use: "orderbook",
|
||||
Short: "orderbook abci++ example",
|
||||
}
|
||||
cli.root.AddCommand(&cobra.Command{
|
||||
Use: "init",
|
||||
Short: "initialize the file system for an orderbook node",
|
||||
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
|
||||
root, err := os.Getwd()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
config.SetRoot(root)
|
||||
cli.config = config
|
||||
return nil
|
||||
},
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
privValKeyFile := cli.config.PrivValidatorKeyFile()
|
||||
privValStateFile := cli.config.PrivValidatorStateFile()
|
||||
var pv *privval.FilePV
|
||||
if tmos.FileExists(privValKeyFile) {
|
||||
pv = privval.LoadFilePV(privValKeyFile, privValStateFile)
|
||||
fmt.Print("found private validator", "keyFile", privValKeyFile,
|
||||
"stateFile", privValStateFile)
|
||||
} else {
|
||||
pv = privval.GenFilePV(privValKeyFile, privValStateFile)
|
||||
pv.Save()
|
||||
fmt.Print("Generated private validator", "keyFile", privValKeyFile,
|
||||
"stateFile", privValStateFile)
|
||||
}
|
||||
|
||||
nodeKeyFile := cli.config.NodeKeyFile()
|
||||
if tmos.FileExists(nodeKeyFile) {
|
||||
fmt.Print("Found node key", "path", nodeKeyFile)
|
||||
} else {
|
||||
if _, err := p2p.LoadOrGenNodeKey(nodeKeyFile); err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Print("Generated node key", "path", nodeKeyFile)
|
||||
}
|
||||
|
||||
// genesis file
|
||||
genFile := cli.config.GenesisFile()
|
||||
if tmos.FileExists(genFile) {
|
||||
fmt.Print("Found genesis file", "path", genFile)
|
||||
} else {
|
||||
genDoc := types.GenesisDoc{
|
||||
ChainID: fmt.Sprintf("orderbook-chain-%v", tmrand.Int()),
|
||||
GenesisTime: tmtime.Now(),
|
||||
ConsensusParams: types.DefaultConsensusParams(),
|
||||
}
|
||||
pubKey, err := pv.GetPubKey()
|
||||
if err != nil {
|
||||
return fmt.Errorf("can't get pubkey: %w", err)
|
||||
}
|
||||
genDoc.Validators = []types.GenesisValidator{{
|
||||
Address: pubKey.Address(),
|
||||
PubKey: pubKey,
|
||||
Power: 10,
|
||||
}}
|
||||
|
||||
if err := genDoc.SaveAs(genFile); err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Print("Generated genesis file", "path", genFile)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
})
|
||||
cli.root.AddCommand(&cobra.Command{
|
||||
Use: "run",
|
||||
Short: "runs an orderbook node",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
dbProvider := node.DefaultDBProvider
|
||||
appDB, err := dbProvider(&node.DBContext{"orderbook", cli.config})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
app, err := orderbook.New(appDB)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
nodeKey, err := p2p.LoadOrGenNodeKey(cli.config.NodeKeyFile())
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to load or gen node key %s: %w", cli.config.NodeKeyFile(), err)
|
||||
}
|
||||
|
||||
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout))
|
||||
n, err := node.NewNode(
|
||||
cli.config,
|
||||
privval.LoadOrGenFilePV(cli.config.PrivValidatorKeyFile(), cli.config.PrivValidatorStateFile()),
|
||||
nodeKey,
|
||||
proxy.NewLocalClientCreator(app),
|
||||
node.DefaultGenesisDocProviderFunc(cli.config),
|
||||
dbProvider,
|
||||
node.DefaultMetricsProvider(cli.config.Instrumentation),
|
||||
logger,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := n.Start(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tmos.TrapSignal(logger, func() {
|
||||
if err := n.Stop(); err != nil {
|
||||
logger.Error("unable to stop the node", "error", err)
|
||||
}
|
||||
})
|
||||
|
||||
return nil
|
||||
},
|
||||
})
|
||||
cli.root.AddCommand(&cobra.Command{
|
||||
Use: "create-account [commodities...]",
|
||||
Short: "creates a new account message and submits it to the chain",
|
||||
Example: "create-account 500BTC 10000USD",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return nil
|
||||
},
|
||||
})
|
||||
cli.root.AddCommand(&cobra.Command{
|
||||
Use: "create-pair buyers-denomination sellers-denomination",
|
||||
Short: "creates a new pair message and submits it to the chain",
|
||||
Example: "create-pair BTC USD",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return nil
|
||||
},
|
||||
})
|
||||
cli.root.AddCommand(&cobra.Command{
|
||||
Use: "bid buying-commodity price",
|
||||
Short: "creates a bid message and submits it to the chain",
|
||||
Example: "bid 10BTC 15000BTC/USD",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return nil
|
||||
},
|
||||
})
|
||||
cli.root.AddCommand(&cobra.Command{
|
||||
Use: "ask selling-commodity price",
|
||||
Short: "creates an ask message and submits it to the chain",
|
||||
Example: "ask 5BTC 12000BTC/USD",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return nil
|
||||
},
|
||||
})
|
||||
querySubcommand := &cobra.Command{
|
||||
Use: "query",
|
||||
Short: "query the bal",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return nil
|
||||
},
|
||||
}
|
||||
querySubcommand.AddCommand(&cobra.Command{
|
||||
Use: "account pubkey|id",
|
||||
Short: "query the balance of an account",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return nil
|
||||
},
|
||||
})
|
||||
querySubcommand.AddCommand(&cobra.Command{
|
||||
Use: "pairs",
|
||||
Short: "list all the trading pairs",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return nil
|
||||
},
|
||||
})
|
||||
querySubcommand.AddCommand(&cobra.Command{
|
||||
Use: "orders pair",
|
||||
Short: "list all current orders for a given pair",
|
||||
Example: "orders BTC/USD",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return nil
|
||||
},
|
||||
})
|
||||
cli.root.AddCommand(querySubcommand)
|
||||
|
||||
return cli
|
||||
}
|
||||
|
||||
// Run runs the CLI.
|
||||
func (cli *CLI) Run() {
|
||||
if err := cli.root.Execute(); err != nil {
|
||||
fmt.Print(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@ package orderbook
|
||||
|
||||
import (
|
||||
fmt "fmt"
|
||||
proto "github.com/cosmos/gogoproto/proto"
|
||||
proto "github.com/gogo/protobuf/proto"
|
||||
io "io"
|
||||
math "math"
|
||||
math_bits "math/bits"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
syntax = "proto3";
|
||||
€syntax = "proto3";
|
||||
|
||||
package orderbook;
|
||||
option go_package = "github.com/tendermint/tendermint/abci/example/orderbook";
|
||||
|
||||
BIN
abci/example/orderbook/orderbook
Executable file
BIN
abci/example/orderbook/orderbook
Executable file
Binary file not shown.
@@ -6,7 +6,7 @@ package orderbook
|
||||
import (
|
||||
encoding_binary "encoding/binary"
|
||||
fmt "fmt"
|
||||
proto "github.com/cosmos/gogoproto/proto"
|
||||
proto "github.com/gogo/protobuf/proto"
|
||||
io "io"
|
||||
math "math"
|
||||
math_bits "math/bits"
|
||||
|
||||
Reference in New Issue
Block a user