-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathnonce.go
123 lines (103 loc) · 2.77 KB
/
nonce.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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
package nonce
import (
"crypto/ed25519"
"errors"
"github.com/mr-tron/base58"
)
var (
ErrNonceNotFound = errors.New("no records could be found")
ErrInvalidNonce = errors.New("invalid nonce")
)
type State uint8
const (
StateUnknown State = iota
StateReleased // The nonce is almost ready but we don't know its blockhash yet.
StateAvailable // The nonce is available to be used by a payment intent, subscription, or other nonce-related transaction.
StateReserved // The nonce is reserved by a payment intent, subscription, or other nonce-related transaction.
StateInvalid // The nonce account is invalid (e.g. insufficient funds, etc).
)
// Split nonce pool across different use cases. This has an added benefit of:
// - Solving for race conditions without distributed locks.
// - Avoiding different use cases from starving each other and ending up in a
// deadlocked state. Concretely, it would be really bad if clients could starve
// internal processes from creating transactions that would allow us to progress
// and submit existing transactions.
type Purpose uint8
const (
PurposeUnknown Purpose = iota
PurposeClientTransaction
PurposeInternalServerProcess
PurposeOnDemandTransaction
)
type Record struct {
Id uint64
Address string
Authority string
Blockhash string
Purpose Purpose
State State
Signature string
}
func (r *Record) GetPublicKey() (ed25519.PublicKey, error) {
return base58.Decode(r.Address)
}
func (r *Record) Clone() Record {
return Record{
Id: r.Id,
Address: r.Address,
Authority: r.Authority,
Blockhash: r.Blockhash,
Purpose: r.Purpose,
State: r.State,
Signature: r.Signature,
}
}
func (r *Record) CopyTo(dst *Record) {
dst.Id = r.Id
dst.Address = r.Address
dst.Authority = r.Authority
dst.Blockhash = r.Blockhash
dst.Purpose = r.Purpose
dst.State = r.State
dst.Signature = r.Signature
}
func (v *Record) Validate() error {
if len(v.Address) == 0 {
return errors.New("nonce account address is required")
}
if len(v.Authority) == 0 {
return errors.New("authority address is required")
}
if v.Purpose == PurposeUnknown {
return errors.New("nonce purpose must be set")
}
return nil
}
func (s State) String() string {
switch s {
case StateUnknown:
return "unknown"
case StateReleased:
return "released"
case StateAvailable:
return "available"
case StateReserved:
return "reserved"
case StateInvalid:
return "invalid"
}
return "unknown"
}
func (p Purpose) String() string {
switch p {
case PurposeUnknown:
return "unknown"
case PurposeClientTransaction:
return "client_transaction"
case PurposeInternalServerProcess:
return "internal_server_process"
case PurposeOnDemandTransaction:
return "on_demand_transaction"
}
return "unknown"
}