Commit 27e96b0e authored by Ralph Pichler's avatar Ralph Pichler Committed by GitHub

don't hold global chequebook lock while sending cheque (#986)

parent 649e64e5
...@@ -73,6 +73,7 @@ type service struct { ...@@ -73,6 +73,7 @@ type service struct {
store storage.StateStorer store storage.StateStorer
chequeSigner ChequeSigner chequeSigner ChequeSigner
totalIssuedReserved *big.Int
} }
// New creates a new chequebook service for the provided chequebook contract. // New creates a new chequebook service for the provided chequebook contract.
...@@ -109,6 +110,7 @@ func New(backend transaction.Backend, transactionService transaction.Service, ad ...@@ -109,6 +110,7 @@ func New(backend transaction.Backend, transactionService transaction.Service, ad
erc20Instance: erc20Instance, erc20Instance: erc20Instance,
store: store, store: store,
chequeSigner: chequeSigner, chequeSigner: chequeSigner,
totalIssuedReserved: big.NewInt(0),
}, nil }, nil
} }
...@@ -202,10 +204,7 @@ func lastIssuedChequeKey(beneficiary common.Address) string { ...@@ -202,10 +204,7 @@ func lastIssuedChequeKey(beneficiary common.Address) string {
return fmt.Sprintf("chequebook_last_issued_cheque_%x", beneficiary) return fmt.Sprintf("chequebook_last_issued_cheque_%x", beneficiary)
} }
// Issue issues a new cheque and passes it to sendChequeFunc func (s *service) reserveTotalIssued(ctx context.Context, amount *big.Int) error {
// if sendChequeFunc succeeds the cheque is considered sent and saved
func (s *service) Issue(ctx context.Context, beneficiary common.Address, amount *big.Int, sendChequeFunc SendChequeFunc) error {
// don't allow concurrent issuing of cheques
s.lock.Lock() s.lock.Lock()
defer s.lock.Unlock() defer s.lock.Unlock()
...@@ -214,10 +213,29 @@ func (s *service) Issue(ctx context.Context, beneficiary common.Address, amount ...@@ -214,10 +213,29 @@ func (s *service) Issue(ctx context.Context, beneficiary common.Address, amount
return err return err
} }
if amount.Cmp(availableBalance) > 0 { if amount.Cmp(big.NewInt(0).Sub(availableBalance, s.totalIssuedReserved)) > 0 {
return ErrOutOfFunds return ErrOutOfFunds
} }
s.totalIssuedReserved = s.totalIssuedReserved.Add(s.totalIssuedReserved, amount)
return nil
}
func (s *service) unreserveTotalIssued(amount *big.Int) {
s.lock.Lock()
defer s.lock.Unlock()
s.totalIssuedReserved = s.totalIssuedReserved.Sub(s.totalIssuedReserved, amount)
}
// Issue issues a new cheque and passes it to sendChequeFunc
// if sendChequeFunc succeeds the cheque is considered sent and saved
func (s *service) Issue(ctx context.Context, beneficiary common.Address, amount *big.Int, sendChequeFunc SendChequeFunc) error {
err := s.reserveTotalIssued(ctx, amount)
if err != nil {
return err
}
defer s.unreserveTotalIssued(amount)
var cumulativePayout *big.Int var cumulativePayout *big.Int
lastCheque, err := s.LastCheque(beneficiary) lastCheque, err := s.LastCheque(beneficiary)
if err != nil { if err != nil {
...@@ -262,6 +280,9 @@ func (s *service) Issue(ctx context.Context, beneficiary common.Address, amount ...@@ -262,6 +280,9 @@ func (s *service) Issue(ctx context.Context, beneficiary common.Address, amount
return err return err
} }
s.lock.Lock()
defer s.lock.Unlock()
totalIssued, err := s.totalIssued() totalIssued, err := s.totalIssued()
if err != nil { if err != nil {
return err return err
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment