-
Notifications
You must be signed in to change notification settings - Fork 0
/
bank.go
94 lines (81 loc) · 2.05 KB
/
bank.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
package coin
import (
"bytes"
"sync"
)
// Bank is a store of balances. It processes transactions but doesn't keep a
// transaction history.
type Bank struct {
sig Signature
bals map[PublicKey]uint32
lock sync.RWMutex
}
// NewBank creates a new bank given a genesis transaction.
func NewBank(trn Transaction) (bnk *Bank, err error) {
// create bank
bnk = new(Bank)
bnk.bals = make(map[PublicKey]uint32)
// amount must not be zero
if trn.Amount == 0 {
err = ErrTrnAmountZero
return
}
// signature must be ok
if !trn.Verify(bnk.Signature()) {
err = ErrTrnBadSignature
return
}
// lock/unlock
bnk.lock.Lock()
defer bnk.lock.Unlock()
// do transaction
bnk.bals[trn.To] = trn.Amount
bnk.sig = trn.Signature
return
}
// Signature returns the current signature of the bank. This is the signature
// of the latest transaction.
func (bnk *Bank) Signature() Signature {
bnk.lock.RLock()
defer bnk.lock.RUnlock()
return bnk.sig
}
// Balance returns the balance of an account in this bank given its public key.
// If the public key has never been used, it returns 0.
func (bnk *Bank) Balance(pubKey PublicKey) uint32 {
bnk.lock.RLock()
defer bnk.lock.RUnlock()
return bnk.bals[pubKey]
}
// Transaction validates and processes the given transaction in the bank. It
// updates the balances of the accounts and the bank's current signature.
func (bnk *Bank) Transaction(trn Transaction) error {
// amount must not be zero
if trn.Amount == 0 {
return ErrTrnAmountZero
}
// sender and receiver must not be the same
if bytes.Equal(trn.From[:], trn.To[:]) {
return ErrTrnSameReceiver
}
// sender must have enough coin
if trn.Amount > bnk.Balance(trn.From) {
return ErrTrnAmountBalance
}
// signature must be ok
if !trn.Verify(bnk.Signature()) {
return ErrTrnBadSignature
}
// lock/unlock
bnk.lock.Lock()
defer bnk.lock.Unlock()
// do transaction
bnk.bals[trn.To] += trn.Amount
bnk.bals[trn.From] -= trn.Amount
bnk.sig = trn.Signature
// cleanup potential zero balance
if bnk.bals[trn.From] == 0 {
delete(bnk.bals, trn.From)
}
return nil
}