diff options
author | Özgür Kesim <oec@codeblau.de> | 2024-04-09 19:24:43 +0200 |
---|---|---|
committer | Özgür Kesim <oec@codeblau.de> | 2024-04-09 19:24:43 +0200 |
commit | 5759f3e45ffad8f1caffbbc68c71b0455da275cb (patch) | |
tree | fd549bfe03c95e9b4d7d2fc538d2e150f7152eba /dashboard/inmemory.go | |
parent | 19ea35f5771af28bd21d462a86ea860d03e29ddb (diff) |
dashboard: started with inmemory dashboard, wip
Diffstat (limited to 'dashboard/inmemory.go')
-rw-r--r-- | dashboard/inmemory.go | 187 |
1 files changed, 187 insertions, 0 deletions
diff --git a/dashboard/inmemory.go b/dashboard/inmemory.go new file mode 100644 index 0000000..82412cb --- /dev/null +++ b/dashboard/inmemory.go @@ -0,0 +1,187 @@ +package dashboard + +import ( + "crypto/ed25519" + "fmt" + "sync" + + "kesim.org/seal" +) + +type inmemory struct { + sync.RWMutex + + auctions map[string]*auction +} + +func NewInMemoryDashboard() *inmemory { + return &inmemory{} +} + +type auction struct { + sync.RWMutex + + description *seal.SignedDescription + state AuctionState + round uint8 // which bit has been completed + + commitments map[string]SignedCommitment + messages map[string][]SignedMessage // per-bidder and per-round messages, pre-allocated. +} + +func (m *inmemory) NewAuction(description *seal.SignedDescription) (auctionId string, e error) { + if ok, e := description.Verify(); e != nil { + return "", e + } else if !ok { + return "", ErrSellerIncorrectSignature + } + + auctionId, e = description.Hash() + if e != nil { + return "", e + } + + auction := &auction{ + description: description, + state: AuctionStateReady, + messages: make(map[string][]SignedMessage), + } + + m.Lock() + defer m.Unlock() + + if _, exists := m.auctions[auctionId]; exists { + return "", ErrSellerAuctionExists + } + m.auctions[auctionId] = auction + + return auctionId, e + +} + +func (m *inmemory) Auctions(state AuctionState) map[string]*seal.SignedDescription { + if state == AuctionStateUnknown || state >= AuctionStateLAST { + return nil + } + + m.RLock() + defer m.RUnlock() + + r := make(map[string]*seal.SignedDescription) + for id, auction := range m.auctions { + if auction.state == state { + r[id] = auction.description + } + } + return r +} + +func (m *inmemory) getAuction(auctionId string) (*auction, error) { + m.RLock() + defer m.RUnlock() + + auction, exists := m.auctions[auctionId] + if !exists { + return nil, ErrAuctionUnknown + + } + + return auction, nil +} + +func (m *inmemory) Join(auctionId string, + commitment SignedCommitment, + pubkey ed25519.PublicKey) error { + + // Check signature first + if !commitment.Verify(pubkey) { + return ErrBidderIncorrectSignature + } + + bidderId := Pub2String(pubkey) + + auction, e := m.getAuction(auctionId) + if e != nil { + return e + } + // We allow overwriting + auction.Lock() + defer auction.Unlock() + if auction.state != AuctionStateReady { + return ErrAuctionNotReady + } + auction.commitments[bidderId] = commitment + auction.messages[bidderId] = make([]SignedMessage, auction.description.BitLength) + + return nil +} + +func (m *inmemory) Commitments(auctionId string) (bidders map[string]SignedCommitment, e error) { + auction, e := m.getAuction(auctionId) + if e != nil { + return nil, e + } + + auction.RLock() + defer auction.RUnlock() + + bidders = make(map[string]SignedCommitment) + for id, commitment := range auction.commitments { + bidders[id] = commitment + } + return bidders, nil +} + +func (m *inmemory) Publish(auctionId string, round uint8, message SignedMessage, pubkey ed25519.PublicKey) error { + if len(message.Message) == 0 { + return ErrBidderEmptyMessage + } + + // check signature first + if !message.Verify(pubkey) { + return ErrBidderIncorrectSignature + } + + bidderId := Pub2String(pubkey) + + auction, e := m.getAuction(auctionId) + if e != nil { + return e + } + + auction.Lock() + defer auction.Unlock() + + if auction.state == AuctionStateFinished { + return ErrAuctionFinished + } else if auction.state != AuctionStateRunning { + return ErrAuctionNotRunning + } else if auction.round != round { + return ErrBidderWrongRound + } + + messages, ok := auction.messages[bidderId] + if !ok { + return ErrBidderUnknown + } + messages[auction.round] = message + + completed := true + + for _, messages := range auction.messages { + completed = completed && len(messages[auction.round].Message) > 0 + } + + if completed { + auction.round += 1 + if auction.round == auction.description.BitLength { + auction.state = AuctionStateFinished + } + } + + return nil +} + +func (m *inmemory) Messages(auctionId string, round uint8) (messages map[string]SignedMessage, e error) { + return nil, fmt.Errorf("inmemory.Messages not implemented") +}
\ No newline at end of file |