From 1f6a6176c094cafb315202ad4325f938f8465313 Mon Sep 17 00:00:00 2001 From: Sam Ricotta Date: Fri, 28 Oct 2022 16:20:59 +0200 Subject: [PATCH] Prepare and process proposal excecution --- abci/example/orderbook/app.go | 226 ++++++++++++++++++-------- abci/example/orderbook/app_test.go | 16 ++ abci/example/orderbook/market_test.go | 27 ++- abci/example/orderbook/msgs.pb.go | 189 +++++++++++++++------ abci/example/orderbook/msgs.proto | 7 +- abci/example/orderbook/types.go | 14 +- abci/example/orderbook/wire.pb.go | 8 +- abci/example/orderbook/wire.proto | 2 +- 8 files changed, 349 insertions(+), 140 deletions(-) create mode 100644 abci/example/orderbook/app_test.go diff --git a/abci/example/orderbook/app.go b/abci/example/orderbook/app.go index c40f8586c..ab14dbfd7 100644 --- a/abci/example/orderbook/app.go +++ b/abci/example/orderbook/app.go @@ -20,12 +20,13 @@ type StateMachine struct { db dbm.DB // in-memory state - accounts map[uint64]*Account + accounts map[uint64]*Account // ephemeral state (not used for the app hash) but for // convienience - pairs map[string]struct{} // lookup pairs - commodity map[string]struct{} // lookup commodities + pairs map[string]struct{} // lookup pairs + commodities map[string]struct{} // lookup commodities + publicKeys map[string]struct{} // lookup existence of an account // app-side mempool (also emphemeral) markets map[string]*Market // i.e. ATOM/USDC @@ -51,15 +52,14 @@ func (sm *StateMachine) CheckTx(req types.RequestCheckTx) types.ResponseCheckTx // validations for each msg below switch m := msg.Sum.(type) { case *Msg_MsgRegisterPair: - // mustnt already have the same pair (also the reverse pairing) - // inbound can also be outbound for pair + if err := m.MsgRegisterPair.ValidateBasic(); err != nil { + return types.ResponseCheckTx{Code: 3} + } case *Msg_MsgCreateAccount: - - if m.MsgCreateAccount.ValidateBasic(); err != nil { + if err := m.MsgCreateAccount.ValidateBasic(); err != nil { return types.ResponseCheckTx{Code: 3} } - //check there is no other account with the same public key case *Msg_MsgBid: @@ -77,8 +77,6 @@ func (sm *StateMachine) CheckTx(req types.RequestCheckTx) types.ResponseCheckTx return types.ResponseCheckTx{Code: 4} } - // check that the account has enough funds to support the bid (quantity * max_price) - case *Msg_MsgAsk: if err := m.MsgAsk.ValidateBasic(); err != nil { @@ -142,12 +140,9 @@ func (sm *StateMachine) BeginBlock(req types.RequestBeginBlock) types.ResponseBe func (sm *StateMachine) DeliverTx(req types.RequestDeliverTx) types.ResponseDeliverTx { tradeSet := new(TradeSet) if err := proto.Unmarshal(req.Tx, tradeSet); err != nil { - panic(fmt.Sprintf("unmarshalling tx: %w", err)) + panic(fmt.Sprintf("unmarshalling tx: %v", err)) } - - - return types.ResponseDeliverTx{Code: 0} } @@ -172,82 +167,177 @@ func (sm *StateMachine) ApplySnapshotChunk(req types.RequestApplySnapshotChunk) } func (sm *StateMachine) PrepareProposal(req types.RequestPrepareProposal) types.ResponsePrepareProposal { - // declare transaction with the size of 0 txs := make([][]byte, 0) // fetch and match all the bids and asks for each market for _, market := range sm.markets { - TradeSet := market.Match(); + tradeSet := market.Match() // tradesets into bytes and bytes into a transaction - if TradeSet == nil { + if tradeSet == nil { continue } - bz, err := proto.Marshal(TradeSet) + + tradeSet = sm.validateTradeSetAgainstState(tradeSet) + if tradeSet == nil || len(tradeSet.MatchedOrders) == 0 { + continue + } + + // wrap this as a message typ + msgTradeSet := &MsgTradeSet{TradeSet: tradeSet} + bz, err := proto.Marshal(msgTradeSet) if err != nil { - return err + panic(err) + } + + // check to see that we don't over populate the block + if len(txs)+len(bz) > int(req.MaxTxBytes) { + return types.ResponsePrepareProposal{Txs: txs} + } + txs = append(txs, bz) + } + + for _, tx := range req.Txs { + var msg = new(Msg) + err := proto.Unmarshal(tx, msg) + if err != nil { + panic(err) + } + + switch m := msg.Sum.(type) { + case *Msg_MsgRegisterPair: + // run the validation checks to see if duplicates within the pairs + pair := m.MsgRegisterPair.Pair + if _, ok := sm.pairs[pair.String()]; ok { + // this pair already exists so we skip over the message + // garbage collection should pick it up + continue + } + + reversePair := &Pair{BuyersDenomination: pair.SellersDenomination, SellersDenomination: pair.BuyersDenomination} + if _, ok := sm.pairs[reversePair.String()]; ok { + // the reverse pair already exists so we skip over it + continue + } + + // check to see that we don't over populate the block + if len(txs)+len(tx) > int(req.MaxTxBytes) { + return types.ResponsePrepareProposal{Txs: txs} + } + txs = append(txs, tx) + + case *Msg_MsgCreateAccount: + // check for duplicate accounts in sm + if _, ok := sm.publicKeys[string(m.MsgCreateAccount.PublicKey)]; ok { + continue + } + + // check to see that we don't over populate the block + if len(txs)+len(tx) > int(req.MaxTxBytes) { + return types.ResponsePrepareProposal{Txs: txs} + } + txs = append(txs, tx) + case *Msg_MsgAsk, *Msg_MsgBid: + // Already have these in the market and are paring together so not necessary to include here + default: + panic(fmt.Sprintf("unknown msg type in prepare proposal %T", m)) } } - // pull in for every single pair - - // does the buyer and seller have sufficient funds - for _, matchedOrder := range tradeSet.MatchedOrders { - bidOwner := sm.accounts[matchedOrder.OrderBid.OwnerId] - askOwner := sm.accounts[matchedOrder.OrderAsk.OwnerId] - - askCommodities := askOwner.Commodities[tradeSet.Pairs.SellersDenomination] - buyCommodities := askOwner.Commodities[tradeSet.Pairs.BuyersDenomination] - - // if bidowner commodities quantity - askowner commodities quantity != 0 then continue - if bidOwner.Commodities[askCommodities.String()] - } - - // // validate the trade: - // - - // // add it to the set of txs - - // } - - // - // } - - // loop through the transactions provided by tendermint and look out for register pair and create account. - // those should still be added. - return types.ResponsePrepareProposal{Txs: req.Txs} } -// Validate matched order +// Process Proposal either rejects or accepts transactions func (sm *StateMachine) ProcessProposal(req types.RequestProcessProposal) types.ResponseProcessProposal { - var msg = new(Msg) + for _, tx := range req.Txs { + var msg = new(Msg) + err := proto.Unmarshal(tx, msg) + if err != nil { + panic(err) + } - err := proto.Unmarshal(req.Txs[], msg) - if err != nil { - return types.ResponseCheckTx{Code: 1} // decoding error + switch m := msg.Sum.(type) { + case *Msg_MsgRegisterPair: + if err := m.MsgRegisterPair.ValidateBasic(); err != nil { + return rejectProposal() + } + + pair := m.MsgRegisterPair.Pair + if _, ok := sm.pairs[pair.String()]; ok { + return rejectProposal() + } + + reversePair := &Pair{BuyersDenomination: pair.SellersDenomination, SellersDenomination: pair.BuyersDenomination} + if _, ok := sm.pairs[reversePair.String()]; ok { + return rejectProposal() + } + + case *Msg_MsgAsk, *Msg_MsgBid: + return rejectProposal() + case *Msg_MsgCreateAccount: + if err := m.MsgCreateAccount.ValidateBasic(); err != nil { + return rejectProposal() + } + + // check for duplicate accounts in sm + if _, ok := sm.publicKeys[string(m.MsgCreateAccount.PublicKey)]; ok { + return rejectProposal() + } + + case *Msg_MsgTradeSet: + if err := m.MsgTradeSet.TradeSet.ValidateBasic(); err != nil { + return rejectProposal() + } + + // for each matched order + // check the accounts exist, that the signatures are valid and that they have the available funds to make the swap + + default: + return rejectProposal() + + } } - // check if there is more than one account - if ok := len(sm.accounts) >= 1; !ok { - return types.ResponseProcessProposal{Code: 4} - } + return acceptProposal() +} + +func (sm *StateMachine) validateTradeSetAgainstState(tradeSet *TradeSet) *TradeSet { + output := &TradeSet{Pair: tradeSet.Pair} + + for _, matchedOrder := range tradeSet.MatchedOrders { + bidOwner := sm.accounts[matchedOrder.OrderBid.OwnerId] + askOwner := sm.accounts[matchedOrder.OrderAsk.OwnerId] + + askCommodities := askOwner.FindCommidity(tradeSet.Pair.SellersDenomination) + if askCommodities == nil { + continue + } + buyCommodities := bidOwner.FindCommidity(tradeSet.Pair.BuyersDenomination) + if buyCommodities == nil { + continue + } + + // Seller has enough of the commodity + if askCommodities.Quantity-matchedOrder.OrderAsk.Quantity < 0 { + continue + } + + // Buyer has enough of the buying commodity + if buyCommodities.Quantity-(matchedOrder.OrderAsk.AskPrice*matchedOrder.OrderAsk.Quantity) < 0 { + continue + } - // check if there is more than one commodity - if ok := len(sm.commodities) >= 1; !ok { - return types.ResponseProcessProposal{Code: 4} + // yayy! this matched order is still valid and can be executed + output.MatchedOrders = append(output.MatchedOrders, matchedOrder) } - // check if there is more than one pair - if ok := len(sm.pairs) >= 1; !ok { - return types.ResponseProcessProposal{Code: 4} - } + return output +} - // check if there is a market - if ok := len(sm.markets) >= 1; !ok { - return types.ResponseProcessProposal{Code: 4} - } +func rejectProposal() types.ResponseProcessProposal { + return types.ResponseProcessProposal{Status: types.ResponseProcessProposal_REJECT} +} - return types.ResponseProcessProposal{ - Status: types.ResponseProcessProposal_ACCEPT} +func acceptProposal() types.ResponseProcessProposal { + return types.ResponseProcessProposal{Status: types.ResponseProcessProposal_ACCEPT} } diff --git a/abci/example/orderbook/app_test.go b/abci/example/orderbook/app_test.go new file mode 100644 index 000000000..617777486 --- /dev/null +++ b/abci/example/orderbook/app_test.go @@ -0,0 +1,16 @@ +package orderbook_test + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/abci/example/orderbook" +) + +func TestPrepareProposal(t *testing.T) { + // check to see if the market collected all of the pairs + market := orderbook.NewMarket(testPair) + require.EqualValues(t, ) +} + diff --git a/abci/example/orderbook/market_test.go b/abci/example/orderbook/market_test.go index 41830394a..f3e2f228b 100644 --- a/abci/example/orderbook/market_test.go +++ b/abci/example/orderbook/market_test.go @@ -72,7 +72,6 @@ func TestSimpleOrderMatching(t *testing.T) { ask: testAsk(40, 10), match: true, }, - } for idx, tc := range testcases { @@ -90,10 +89,10 @@ func TestSimpleOrderMatching(t *testing.T) { func TestMultiOrderMatching(t *testing.T) { testcases := []struct { - bids []*orderbook.OrderBid - asks []*orderbook.OrderAsk - expected []*orderbook.MatchedOrder - expectedLowestAsk float64 + bids []*orderbook.OrderBid + asks []*orderbook.OrderAsk + expected []*orderbook.MatchedOrder + expectedLowestAsk float64 expectedHighestBid float64 }{ { @@ -115,8 +114,8 @@ func TestMultiOrderMatching(t *testing.T) { OrderAsk: testAsk(30, 15), OrderBid: testBid(50, 20), }, - }, - expectedLowestAsk: 0, + }, + expectedLowestAsk: 0, expectedHighestBid: 40, }, { @@ -134,8 +133,8 @@ func TestMultiOrderMatching(t *testing.T) { OrderAsk: testAsk(60, 15), OrderBid: testBid(60, 20), }, - }, - expectedLowestAsk: 50, + }, + expectedLowestAsk: 50, expectedHighestBid: 80, }, { @@ -143,9 +142,9 @@ func TestMultiOrderMatching(t *testing.T) { testBid(60, 20), testBid(80, 5), }, - asks: []*orderbook.OrderAsk{}, - expected: []*orderbook.MatchedOrder{}, - expectedLowestAsk: 0, + asks: []*orderbook.OrderAsk{}, + expected: []*orderbook.MatchedOrder{}, + expectedLowestAsk: 0, expectedHighestBid: 80, }, { @@ -154,8 +153,8 @@ func TestMultiOrderMatching(t *testing.T) { testAsk(70, 10), testAsk(50, 20), }, - expected: []*orderbook.MatchedOrder{}, - expectedLowestAsk: 50, + expected: []*orderbook.MatchedOrder{}, + expectedLowestAsk: 50, expectedHighestBid: 0, }, } diff --git a/abci/example/orderbook/msgs.pb.go b/abci/example/orderbook/msgs.pb.go index c8011fb5e..35a198f6a 100644 --- a/abci/example/orderbook/msgs.pb.go +++ b/abci/example/orderbook/msgs.pb.go @@ -135,7 +135,7 @@ type MsgCreateAccount struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - PublicKey [][]byte `protobuf:"bytes,1,rep,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"` + PublicKey []byte `protobuf:"bytes,1,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"` Commodities []*Commodity `protobuf:"bytes,2,rep,name=commodities,proto3" json:"commodities,omitempty"` } @@ -171,7 +171,7 @@ func (*MsgCreateAccount) Descriptor() ([]byte, []int) { return file_msgs_proto_rawDescGZIP(), []int{2} } -func (x *MsgCreateAccount) GetPublicKey() [][]byte { +func (x *MsgCreateAccount) GetPublicKey() []byte { if x != nil { return x.PublicKey } @@ -232,25 +232,74 @@ func (x *MsgRegisterPair) GetPair() *Pair { return nil } +type MsgTradeSet struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + TradeSet *TradeSet `protobuf:"bytes,1,opt,name=trade_set,json=tradeSet,proto3" json:"trade_set,omitempty"` +} + +func (x *MsgTradeSet) Reset() { + *x = MsgTradeSet{} + if protoimpl.UnsafeEnabled { + mi := &file_msgs_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MsgTradeSet) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MsgTradeSet) ProtoMessage() {} + +func (x *MsgTradeSet) ProtoReflect() protoreflect.Message { + mi := &file_msgs_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MsgTradeSet.ProtoReflect.Descriptor instead. +func (*MsgTradeSet) Descriptor() ([]byte, []int) { + return file_msgs_proto_rawDescGZIP(), []int{4} +} + +func (x *MsgTradeSet) GetTradeSet() *TradeSet { + if x != nil { + return x.TradeSet + } + return nil +} + type Msg struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - //a Msg has to be one of the below + // a Msg has to be one of the below // // Types that are assignable to Sum: + // // *Msg_MsgBid // *Msg_MsgAsk // *Msg_MsgRegisterPair // *Msg_MsgCreateAccount + // *Msg_MsgTradeSet Sum isMsg_Sum `protobuf_oneof:"sum"` } func (x *Msg) Reset() { *x = Msg{} if protoimpl.UnsafeEnabled { - mi := &file_msgs_proto_msgTypes[4] + mi := &file_msgs_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -263,7 +312,7 @@ func (x *Msg) String() string { func (*Msg) ProtoMessage() {} func (x *Msg) ProtoReflect() protoreflect.Message { - mi := &file_msgs_proto_msgTypes[4] + mi := &file_msgs_proto_msgTypes[5] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -276,7 +325,7 @@ func (x *Msg) ProtoReflect() protoreflect.Message { // Deprecated: Use Msg.ProtoReflect.Descriptor instead. func (*Msg) Descriptor() ([]byte, []int) { - return file_msgs_proto_rawDescGZIP(), []int{4} + return file_msgs_proto_rawDescGZIP(), []int{5} } func (m *Msg) GetSum() isMsg_Sum { @@ -314,6 +363,13 @@ func (x *Msg) GetMsgCreateAccount() *MsgCreateAccount { return nil } +func (x *Msg) GetMsgTradeSet() *MsgTradeSet { + if x, ok := x.GetSum().(*Msg_MsgTradeSet); ok { + return x.MsgTradeSet + } + return nil +} + type isMsg_Sum interface { isMsg_Sum() } @@ -334,6 +390,10 @@ type Msg_MsgCreateAccount struct { MsgCreateAccount *MsgCreateAccount `protobuf:"bytes,4,opt,name=msg_create_account,json=msgCreateAccount,proto3,oneof"` } +type Msg_MsgTradeSet struct { + MsgTradeSet *MsgTradeSet `protobuf:"bytes,5,opt,name=msg_trade_set,json=msgTradeSet,proto3,oneof"` +} + func (*Msg_MsgBid) isMsg_Sum() {} func (*Msg_MsgAsk) isMsg_Sum() {} @@ -342,6 +402,8 @@ func (*Msg_MsgRegisterPair) isMsg_Sum() {} func (*Msg_MsgCreateAccount) isMsg_Sum() {} +func (*Msg_MsgTradeSet) isMsg_Sum() {} + var File_msgs_proto protoreflect.FileDescriptor var file_msgs_proto_rawDesc = []byte{ @@ -361,7 +423,7 @@ var file_msgs_proto_rawDesc = []byte{ 0x6f, 0x6b, 0x2e, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x41, 0x73, 0x6b, 0x52, 0x08, 0x61, 0x73, 0x6b, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x22, 0x69, 0x0a, 0x10, 0x4d, 0x73, 0x67, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x75, 0x62, - 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x09, 0x70, + 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x36, 0x0a, 0x0b, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x64, 0x69, 0x74, 0x69, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x62, 0x6f, 0x6f, 0x6b, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x64, @@ -369,27 +431,35 @@ var file_msgs_proto_rawDesc = []byte{ 0x22, 0x36, 0x0a, 0x0f, 0x4d, 0x73, 0x67, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, 0x61, 0x69, 0x72, 0x12, 0x23, 0x0a, 0x04, 0x70, 0x61, 0x69, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x62, 0x6f, 0x6f, 0x6b, 0x2e, 0x50, 0x61, - 0x69, 0x72, 0x52, 0x04, 0x70, 0x61, 0x69, 0x72, 0x22, 0xff, 0x01, 0x0a, 0x03, 0x4d, 0x73, 0x67, - 0x12, 0x2c, 0x0a, 0x07, 0x6d, 0x73, 0x67, 0x5f, 0x62, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x11, 0x2e, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x62, 0x6f, 0x6f, 0x6b, 0x2e, 0x4d, 0x73, - 0x67, 0x42, 0x69, 0x64, 0x48, 0x00, 0x52, 0x06, 0x6d, 0x73, 0x67, 0x42, 0x69, 0x64, 0x12, 0x2c, - 0x0a, 0x07, 0x6d, 0x73, 0x67, 0x5f, 0x61, 0x73, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x11, 0x2e, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x62, 0x6f, 0x6f, 0x6b, 0x2e, 0x4d, 0x73, 0x67, 0x41, - 0x73, 0x6b, 0x48, 0x00, 0x52, 0x06, 0x6d, 0x73, 0x67, 0x41, 0x73, 0x6b, 0x12, 0x48, 0x0a, 0x11, - 0x6d, 0x73, 0x67, 0x5f, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x70, 0x61, 0x69, - 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x62, - 0x6f, 0x6f, 0x6b, 0x2e, 0x4d, 0x73, 0x67, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, - 0x61, 0x69, 0x72, 0x48, 0x00, 0x52, 0x0f, 0x6d, 0x73, 0x67, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, - 0x65, 0x72, 0x50, 0x61, 0x69, 0x72, 0x12, 0x4b, 0x0a, 0x12, 0x6d, 0x73, 0x67, 0x5f, 0x63, 0x72, - 0x65, 0x61, 0x74, 0x65, 0x5f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x62, 0x6f, 0x6f, 0x6b, 0x2e, 0x4d, - 0x73, 0x67, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x48, - 0x00, 0x52, 0x10, 0x6d, 0x73, 0x67, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x63, 0x63, 0x6f, - 0x75, 0x6e, 0x74, 0x42, 0x05, 0x0a, 0x03, 0x73, 0x75, 0x6d, 0x42, 0x39, 0x5a, 0x37, 0x67, 0x69, - 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x74, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x6d, - 0x69, 0x6e, 0x74, 0x2f, 0x74, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x74, 0x2f, 0x61, - 0x62, 0x63, 0x69, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x6f, 0x72, 0x64, 0x65, - 0x72, 0x62, 0x6f, 0x6f, 0x6b, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x69, 0x72, 0x52, 0x04, 0x70, 0x61, 0x69, 0x72, 0x22, 0x3f, 0x0a, 0x0b, 0x4d, 0x73, 0x67, 0x54, + 0x72, 0x61, 0x64, 0x65, 0x53, 0x65, 0x74, 0x12, 0x30, 0x0a, 0x09, 0x74, 0x72, 0x61, 0x64, 0x65, + 0x5f, 0x73, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x6f, 0x72, 0x64, + 0x65, 0x72, 0x62, 0x6f, 0x6f, 0x6b, 0x2e, 0x54, 0x72, 0x61, 0x64, 0x65, 0x53, 0x65, 0x74, 0x52, + 0x08, 0x74, 0x72, 0x61, 0x64, 0x65, 0x53, 0x65, 0x74, 0x22, 0xbd, 0x02, 0x0a, 0x03, 0x4d, 0x73, + 0x67, 0x12, 0x2c, 0x0a, 0x07, 0x6d, 0x73, 0x67, 0x5f, 0x62, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x62, 0x6f, 0x6f, 0x6b, 0x2e, 0x4d, + 0x73, 0x67, 0x42, 0x69, 0x64, 0x48, 0x00, 0x52, 0x06, 0x6d, 0x73, 0x67, 0x42, 0x69, 0x64, 0x12, + 0x2c, 0x0a, 0x07, 0x6d, 0x73, 0x67, 0x5f, 0x61, 0x73, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x11, 0x2e, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x62, 0x6f, 0x6f, 0x6b, 0x2e, 0x4d, 0x73, 0x67, + 0x41, 0x73, 0x6b, 0x48, 0x00, 0x52, 0x06, 0x6d, 0x73, 0x67, 0x41, 0x73, 0x6b, 0x12, 0x48, 0x0a, + 0x11, 0x6d, 0x73, 0x67, 0x5f, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x70, 0x61, + 0x69, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6f, 0x72, 0x64, 0x65, 0x72, + 0x62, 0x6f, 0x6f, 0x6b, 0x2e, 0x4d, 0x73, 0x67, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, + 0x50, 0x61, 0x69, 0x72, 0x48, 0x00, 0x52, 0x0f, 0x6d, 0x73, 0x67, 0x52, 0x65, 0x67, 0x69, 0x73, + 0x74, 0x65, 0x72, 0x50, 0x61, 0x69, 0x72, 0x12, 0x4b, 0x0a, 0x12, 0x6d, 0x73, 0x67, 0x5f, 0x63, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x62, 0x6f, 0x6f, 0x6b, 0x2e, + 0x4d, 0x73, 0x67, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, + 0x48, 0x00, 0x52, 0x10, 0x6d, 0x73, 0x67, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x63, 0x63, + 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x3c, 0x0a, 0x0d, 0x6d, 0x73, 0x67, 0x5f, 0x74, 0x72, 0x61, 0x64, + 0x65, 0x5f, 0x73, 0x65, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6f, 0x72, + 0x64, 0x65, 0x72, 0x62, 0x6f, 0x6f, 0x6b, 0x2e, 0x4d, 0x73, 0x67, 0x54, 0x72, 0x61, 0x64, 0x65, + 0x53, 0x65, 0x74, 0x48, 0x00, 0x52, 0x0b, 0x6d, 0x73, 0x67, 0x54, 0x72, 0x61, 0x64, 0x65, 0x53, + 0x65, 0x74, 0x42, 0x05, 0x0a, 0x03, 0x73, 0x75, 0x6d, 0x42, 0x39, 0x5a, 0x37, 0x67, 0x69, 0x74, + 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x74, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x6d, 0x69, + 0x6e, 0x74, 0x2f, 0x74, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x74, 0x2f, 0x61, 0x62, + 0x63, 0x69, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x6f, 0x72, 0x64, 0x65, 0x72, + 0x62, 0x6f, 0x6f, 0x6b, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -404,34 +474,38 @@ func file_msgs_proto_rawDescGZIP() []byte { return file_msgs_proto_rawDescData } -var file_msgs_proto_msgTypes = make([]protoimpl.MessageInfo, 5) +var file_msgs_proto_msgTypes = make([]protoimpl.MessageInfo, 6) var file_msgs_proto_goTypes = []interface{}{ (*MsgBid)(nil), // 0: orderbook.MsgBid (*MsgAsk)(nil), // 1: orderbook.MsgAsk (*MsgCreateAccount)(nil), // 2: orderbook.MsgCreateAccount (*MsgRegisterPair)(nil), // 3: orderbook.MsgRegisterPair - (*Msg)(nil), // 4: orderbook.Msg - (*Pair)(nil), // 5: orderbook.Pair - (*OrderBid)(nil), // 6: orderbook.OrderBid - (*OrderAsk)(nil), // 7: orderbook.OrderAsk - (*Commodity)(nil), // 8: orderbook.Commodity + (*MsgTradeSet)(nil), // 4: orderbook.MsgTradeSet + (*Msg)(nil), // 5: orderbook.Msg + (*Pair)(nil), // 6: orderbook.Pair + (*OrderBid)(nil), // 7: orderbook.OrderBid + (*OrderAsk)(nil), // 8: orderbook.OrderAsk + (*Commodity)(nil), // 9: orderbook.Commodity + (*TradeSet)(nil), // 10: orderbook.TradeSet } var file_msgs_proto_depIdxs = []int32{ - 5, // 0: orderbook.MsgBid.pair:type_name -> orderbook.Pair - 6, // 1: orderbook.MsgBid.bid_order:type_name -> orderbook.OrderBid - 5, // 2: orderbook.MsgAsk.pair:type_name -> orderbook.Pair - 7, // 3: orderbook.MsgAsk.ask_order:type_name -> orderbook.OrderAsk - 8, // 4: orderbook.MsgCreateAccount.commodities:type_name -> orderbook.Commodity - 5, // 5: orderbook.MsgRegisterPair.pair:type_name -> orderbook.Pair - 0, // 6: orderbook.Msg.msg_bid:type_name -> orderbook.MsgBid - 1, // 7: orderbook.Msg.msg_ask:type_name -> orderbook.MsgAsk - 3, // 8: orderbook.Msg.msg_register_pair:type_name -> orderbook.MsgRegisterPair - 2, // 9: orderbook.Msg.msg_create_account:type_name -> orderbook.MsgCreateAccount - 10, // [10:10] is the sub-list for method output_type - 10, // [10:10] is the sub-list for method input_type - 10, // [10:10] is the sub-list for extension type_name - 10, // [10:10] is the sub-list for extension extendee - 0, // [0:10] is the sub-list for field type_name + 6, // 0: orderbook.MsgBid.pair:type_name -> orderbook.Pair + 7, // 1: orderbook.MsgBid.bid_order:type_name -> orderbook.OrderBid + 6, // 2: orderbook.MsgAsk.pair:type_name -> orderbook.Pair + 8, // 3: orderbook.MsgAsk.ask_order:type_name -> orderbook.OrderAsk + 9, // 4: orderbook.MsgCreateAccount.commodities:type_name -> orderbook.Commodity + 6, // 5: orderbook.MsgRegisterPair.pair:type_name -> orderbook.Pair + 10, // 6: orderbook.MsgTradeSet.trade_set:type_name -> orderbook.TradeSet + 0, // 7: orderbook.Msg.msg_bid:type_name -> orderbook.MsgBid + 1, // 8: orderbook.Msg.msg_ask:type_name -> orderbook.MsgAsk + 3, // 9: orderbook.Msg.msg_register_pair:type_name -> orderbook.MsgRegisterPair + 2, // 10: orderbook.Msg.msg_create_account:type_name -> orderbook.MsgCreateAccount + 4, // 11: orderbook.Msg.msg_trade_set:type_name -> orderbook.MsgTradeSet + 12, // [12:12] is the sub-list for method output_type + 12, // [12:12] is the sub-list for method input_type + 12, // [12:12] is the sub-list for extension type_name + 12, // [12:12] is the sub-list for extension extendee + 0, // [0:12] is the sub-list for field type_name } func init() { file_msgs_proto_init() } @@ -490,6 +564,18 @@ func file_msgs_proto_init() { } } file_msgs_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MsgTradeSet); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_msgs_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Msg); i { case 0: return &v.state @@ -502,11 +588,12 @@ func file_msgs_proto_init() { } } } - file_msgs_proto_msgTypes[4].OneofWrappers = []interface{}{ + file_msgs_proto_msgTypes[5].OneofWrappers = []interface{}{ (*Msg_MsgBid)(nil), (*Msg_MsgAsk)(nil), (*Msg_MsgRegisterPair)(nil), (*Msg_MsgCreateAccount)(nil), + (*Msg_MsgTradeSet)(nil), } type x struct{} out := protoimpl.TypeBuilder{ @@ -514,7 +601,7 @@ func file_msgs_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_msgs_proto_rawDesc, NumEnums: 0, - NumMessages: 5, + NumMessages: 6, NumExtensions: 0, NumServices: 0, }, diff --git a/abci/example/orderbook/msgs.proto b/abci/example/orderbook/msgs.proto index 89e82d709..95a28a148 100644 --- a/abci/example/orderbook/msgs.proto +++ b/abci/example/orderbook/msgs.proto @@ -16,7 +16,7 @@ message MsgAsk { } message MsgCreateAccount { - repeated bytes public_key = 1; + bytes public_key = 1; repeated Commodity commodities = 2; } @@ -24,6 +24,10 @@ message MsgRegisterPair { Pair pair = 1; } +message MsgTradeSet { + TradeSet trade_set = 1; +} + message Msg { //a Msg has to be one of the below oneof sum { @@ -31,5 +35,6 @@ message Msg { MsgAsk msg_ask = 2; MsgRegisterPair msg_register_pair = 3; MsgCreateAccount msg_create_account = 4; + MsgTradeSet msg_trade_set = 5; } } \ No newline at end of file diff --git a/abci/example/orderbook/types.go b/abci/example/orderbook/types.go index 4c8dcc7f1..bd1298360 100644 --- a/abci/example/orderbook/types.go +++ b/abci/example/orderbook/types.go @@ -98,10 +98,22 @@ func (o *OrderBid) ValidateBasic() error { if o.MaxPrice <= 0 { return errors.New("min price must be greater than 0") } - + return nil } +func (m *MatchedOrder) ValidateBasic() error { + if len(m.OrderAsk.Signature) != ed25519.SignatureSize { + return errors.New("invalid signature size") + } +} + +func (t *TradeSet) ValidateBasic() error { + return t.Pair.ValidateBasic() + return t.MatchedOrders.ValidateBasic() + +} + func (o *OrderAsk) ValidateBasic() error { if o.Quantity == 0 { return errors.New("quantity outbound must be non zero") diff --git a/abci/example/orderbook/wire.pb.go b/abci/example/orderbook/wire.pb.go index fc00b6fb2..e6d65fbed 100644 --- a/abci/example/orderbook/wire.pb.go +++ b/abci/example/orderbook/wire.pb.go @@ -279,8 +279,8 @@ type Account struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Index uint64 `protobuf:"varint,1,opt,name=index,proto3" json:"index,omitempty"` - PublicKey [][]byte `protobuf:"bytes,2,rep,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"` + Index uint64 `protobuf:"varint,1,opt,name=index,proto3" json:"index,omitempty"` + PublicKey []byte `protobuf:"bytes,2,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"` // the set of commodities that the account has Commodities []*Commodity `protobuf:"bytes,3,rep,name=commodities,proto3" json:"commodities,omitempty"` } @@ -324,7 +324,7 @@ func (x *Account) GetIndex() uint64 { return 0 } -func (x *Account) GetPublicKey() [][]byte { +func (x *Account) GetPublicKey() []byte { if x != nil { return x.PublicKey } @@ -485,7 +485,7 @@ var file_wire_proto_rawDesc = []byte{ 0x61, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x22, 0x76, 0x0a, 0x07, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x75, 0x62, 0x6c, 0x69, - 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x09, 0x70, 0x75, 0x62, + 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x36, 0x0a, 0x0b, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x64, 0x69, 0x74, 0x69, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x62, 0x6f, 0x6f, 0x6b, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x64, 0x69, 0x74, diff --git a/abci/example/orderbook/wire.proto b/abci/example/orderbook/wire.proto index 9ded9ae30..babc7ad5a 100644 --- a/abci/example/orderbook/wire.proto +++ b/abci/example/orderbook/wire.proto @@ -32,7 +32,7 @@ message Commodity { message Account { uint64 index = 1; - repeated bytes public_key = 2; + bytes public_key = 2; // the set of commodities that the account has repeated Commodity commodities = 3; }