@@ -5,9 +5,11 @@ import (
55 "math/rand"
66 "sort"
77 "sync"
8+ "time"
89
910 "github.com/code-payments/code-server/pkg/code/data/nonce"
1011 "github.com/code-payments/code-server/pkg/database/query"
12+ "github.com/code-payments/code-server/pkg/pointer"
1113)
1214
1315type store struct {
@@ -131,6 +133,16 @@ func (s *store) filter(items []*nonce.Record, cursor query.Cursor, limit uint64,
131133 return res
132134}
133135
136+ func (s * store ) filterAvailable (items []* nonce.Record ) []* nonce.Record {
137+ var res []* nonce.Record
138+ for _ , item := range items {
139+ if item .IsAvailable () {
140+ res = append (res , item )
141+ }
142+ }
143+ return res
144+ }
145+
134146func (s * store ) Count (ctx context.Context , env nonce.Environment , instance string ) (uint64 , error ) {
135147 s .mu .Lock ()
136148 defer s .mu .Unlock ()
@@ -165,13 +177,25 @@ func (s *store) Save(ctx context.Context, data *nonce.Record) error {
165177
166178 s .last ++
167179 if item := s .find (data ); item != nil {
180+ if item .Version != data .Version {
181+ return nonce .ErrStaleVersion
182+ }
183+
184+ data .Version ++
185+
168186 item .Blockhash = data .Blockhash
169- item .State = data .State
170187 item .Signature = data .Signature
188+ item .State = data .State
189+ item .ClaimNodeID = pointer .StringCopy (data .ClaimNodeID )
190+ item .ClaimExpiresAt = pointer .TimeCopy (data .ClaimExpiresAt )
191+ item .Version = data .Version
171192 } else {
172193 if data .Id == 0 {
173194 data .Id = s .last
174195 }
196+
197+ data .Version ++
198+
175199 c := data .Clone ()
176200 s .records = append (s .records , & c )
177201 }
@@ -184,7 +208,8 @@ func (s *store) Get(ctx context.Context, address string) (*nonce.Record, error)
184208 defer s .mu .Unlock ()
185209
186210 if item := s .findAddress (address ); item != nil {
187- return item , nil
211+ cloned := item .Clone ()
212+ return & cloned , nil
188213 }
189214
190215 return nil , nonce .ErrNonceNotFound
@@ -201,7 +226,7 @@ func (s *store) GetAllByState(ctx context.Context, env nonce.Environment, instan
201226 return nil , nonce .ErrNonceNotFound
202227 }
203228
204- return res , nil
229+ return clonedRecords ( res ) , nil
205230 }
206231
207232 return nil , nonce .ErrNonceNotFound
@@ -212,10 +237,53 @@ func (s *store) GetRandomAvailableByPurpose(ctx context.Context, env nonce.Envir
212237 defer s .mu .Unlock ()
213238
214239 items := s .findByStateAndPurpose (env , instance , nonce .StateAvailable , purpose )
240+ items = append (items , s .findByStateAndPurpose (env , instance , nonce .StateClaimed , purpose )... )
241+ items = s .filterAvailable (items )
215242 if len (items ) == 0 {
216243 return nil , nonce .ErrNonceNotFound
217244 }
218245
219246 index := rand .Intn (len (items ))
220- return items [index ], nil
247+ cloned := items [index ].Clone ()
248+ return & cloned , nil
249+ }
250+
251+ func (s * store ) BatchClaimAvailableByPurpose (ctx context.Context , env nonce.Environment , instance string , purpose nonce.Purpose , limit int , nodeID string , minExpireAt , maxExpireAt time.Time ) ([]* nonce.Record , error ) {
252+ s .mu .Lock ()
253+ defer s .mu .Unlock ()
254+
255+ items := s .findByStateAndPurpose (env , instance , nonce .StateAvailable , purpose )
256+ items = append (items , s .findByStateAndPurpose (env , instance , nonce .StateClaimed , purpose )... )
257+ items = s .filterAvailable (items )
258+ if len (items ) == 0 {
259+ return nil , nonce .ErrNonceNotFound
260+ }
261+ if len (items ) > limit {
262+ items = items [:limit ]
263+ }
264+
265+ for i , l := 0 , len (items ); i < l ; i ++ {
266+ j := rand .Intn (l )
267+ items [i ], items [j ] = items [j ], items [i ]
268+ }
269+ for i := 0 ; i < len (items ); i ++ {
270+ window := maxExpireAt .Sub (minExpireAt )
271+ expiry := minExpireAt .Add (time .Duration (rand .Intn (int (window ))))
272+
273+ items [i ].State = nonce .StateClaimed
274+ items [i ].ClaimNodeID = pointer .String (nodeID )
275+ items [i ].ClaimExpiresAt = pointer .Time (expiry )
276+ items [i ].Version ++
277+ }
278+
279+ return clonedRecords (items ), nil
280+ }
281+
282+ func clonedRecords (items []* nonce.Record ) []* nonce.Record {
283+ res := make ([]* nonce.Record , len (items ))
284+ for i , item := range items {
285+ cloned := item .Clone ()
286+ res [i ] = & cloned
287+ }
288+ return res
221289}
0 commit comments