aboutsummaryrefslogtreecommitdiff
path: root/dashboard/inmemory.go
diff options
context:
space:
mode:
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
commit5759f3e45ffad8f1caffbbc68c71b0455da275cb (patch)
treefd549bfe03c95e9b4d7d2fc538d2e150f7152eba /dashboard/inmemory.go
parent19ea35f5771af28bd21d462a86ea860d03e29ddb (diff)
dashboard: started with inmemory dashboard, wip
Diffstat (limited to 'dashboard/inmemory.go')
-rw-r--r--dashboard/inmemory.go187
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