mirror of
https://github.com/tendermint/tendermint.git
synced 2026-04-16 05:37:17 +00:00
add more documentation
This commit is contained in:
@@ -1,4 +1,19 @@
|
||||
//go:generate go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
|
||||
//go:generate protoc -I. -I../.. --go_out=. --go_opt=paths=source_relative wire.proto msgs.proto
|
||||
|
||||
// The orderbook presents a more advanced example of a Tendermint application than the simple kvstore
|
||||
//
|
||||
// An orderbook is a tool used in financial markets for enabling trading of various commodities. Without
|
||||
// delving into too much detail, an orderbook is made of two types of transactions: Bids and Asks. An Ask
|
||||
// is an offer by a seller for n amount of a commodity at an AskPrice and a bid is an offer from a buyer
|
||||
// for m amount of a commodity at a BidPrice. When the bid price exceeds the ask price, and the buyer quantity
|
||||
// is less than or equal to the sellers quantity, the order is matched. In actual terms, we neglect the
|
||||
// underlying denomination (i.e. USD) and effectively both participants are simultaneously a buyer and seller.
|
||||
//
|
||||
// This example falls far short of being a decentralized orderbook, but demonstrates how one can build an
|
||||
// app-side mempool, how one can use PrepareProposal and ProcessProposal to craft complex transactions,
|
||||
// how we can use signatures and validate transactions against state. How applications can manage concurrency,
|
||||
// and demonstrate the lifecycle of transactions from RPC -> CheckTx -> Mempool -> PrepareProposal -> ProcessProposal
|
||||
// -> DeliverTx -> Commit -> Querying
|
||||
|
||||
package orderbook
|
||||
|
||||
@@ -2,10 +2,14 @@ package orderbook
|
||||
|
||||
import (
|
||||
"container/heap"
|
||||
sync "sync"
|
||||
)
|
||||
|
||||
type Market struct {
|
||||
pair *Pair // i.e. EUR/USD (a market is bidirectional)
|
||||
// immutable
|
||||
pair *Pair // i.e. EUR/USD (a market is bidirectional)
|
||||
|
||||
mtx sync.RWMutex
|
||||
askOrders *AskOrders // i.e. buying EUR for USD
|
||||
lowestAsk float64
|
||||
bidOrders *BidOrders // i.e. selling EUR for USD or buying USD for EUR
|
||||
@@ -19,6 +23,8 @@ func NewMarket(p *Pair) *Market {
|
||||
}
|
||||
|
||||
func (m *Market) AddBid(b *OrderBid) {
|
||||
m.mtx.Lock()
|
||||
defer m.mtx.Unlock()
|
||||
heap.Push(m.bidOrders, b)
|
||||
if b.MaxPrice > m.highestBid {
|
||||
m.highestBid = b.MaxPrice
|
||||
@@ -26,6 +32,8 @@ func (m *Market) AddBid(b *OrderBid) {
|
||||
}
|
||||
|
||||
func (m *Market) AddAsk(a *OrderAsk) {
|
||||
m.mtx.Lock()
|
||||
defer m.mtx.Unlock()
|
||||
heap.Push(m.askOrders, a)
|
||||
if a.AskPrice < m.lowestAsk || m.lowestAsk == 0 {
|
||||
m.lowestAsk = a.AskPrice
|
||||
@@ -36,6 +44,8 @@ func (m *Market) AddAsk(a *OrderAsk) {
|
||||
// A bid matches an ask when the MaxPrice is greater than the AskPrice
|
||||
// and the MaxQuantity is greater than the quantity.
|
||||
func (m *Market) Match() *TradeSet {
|
||||
m.mtx.Lock()
|
||||
defer m.mtx.Unlock()
|
||||
// if one side doesn't have any orders than there is nothing to match
|
||||
// and we return early
|
||||
if m.askOrders.Len() == 0 || m.bidOrders.Len() == 0 {
|
||||
@@ -147,13 +157,37 @@ OUTER_LOOP:
|
||||
}
|
||||
|
||||
func (m Market) LowestAsk() float64 {
|
||||
m.mtx.RLock()
|
||||
defer m.mtx.RUnlock()
|
||||
return m.lowestAsk
|
||||
}
|
||||
|
||||
func (m Market) HighestBid() float64 {
|
||||
m.mtx.RLock()
|
||||
defer m.mtx.RUnlock()
|
||||
return m.highestBid
|
||||
}
|
||||
|
||||
func (m Market) GetBids() []OrderBid {
|
||||
m.mtx.RLock()
|
||||
defer m.mtx.RUnlock()
|
||||
orders := make([]OrderBid, m.bidOrders.Len())
|
||||
for idx, order := range *m.bidOrders {
|
||||
orders[idx] = *order
|
||||
}
|
||||
return orders
|
||||
}
|
||||
|
||||
func (m Market) GetAsks() []OrderAsk {
|
||||
m.mtx.RLock()
|
||||
defer m.mtx.RUnlock()
|
||||
orders := make([]OrderAsk, m.askOrders.Len())
|
||||
for idx, order := range *m.askOrders {
|
||||
orders[idx] = *order
|
||||
}
|
||||
return orders
|
||||
}
|
||||
|
||||
// Heap ordered by lowest price
|
||||
type AskOrders []*OrderAsk
|
||||
|
||||
|
||||
31
abci/example/orderbook/query.go
Normal file
31
abci/example/orderbook/query.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package orderbook
|
||||
|
||||
// Query the state of an account (returns a concrete copy)
|
||||
func (sm *StateMachine) Account(id uint64) Account {
|
||||
if int(id) >= len(sm.accounts) {
|
||||
return Account{}
|
||||
}
|
||||
return *sm.accounts[id]
|
||||
}
|
||||
|
||||
// Query all the pairs that the orderbook has (returns a concrete copy)
|
||||
func (sm *StateMachine) Pairs() []Pair {
|
||||
pairs := make([]Pair, len(sm.pairs))
|
||||
idx := 0
|
||||
for _, pair := range sm.pairs {
|
||||
pairs[idx] = *pair
|
||||
idx++
|
||||
}
|
||||
return pairs
|
||||
}
|
||||
|
||||
// Query the current orders for a pair (returns concrete copies)
|
||||
func (sm *StateMachine) Orders(pair *Pair) ([]OrderBid, []OrderAsk) {
|
||||
market, ok := sm.markets[pair.String()]
|
||||
if !ok {
|
||||
return nil, nil
|
||||
}
|
||||
return market.GetBids(), market.GetAsks()
|
||||
}
|
||||
|
||||
func (sm *StateMachine) Height() int64 { return sm.lastHeight }
|
||||
Reference in New Issue
Block a user