antd 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +85 -1
- data/lib/antd/client.rb +40 -27
- data/lib/antd/errors.rb +224 -0
- data/lib/antd/grpc_client.rb +53 -1
- data/lib/antd/v1/chunks_pb.rb +1 -1
- data/lib/antd/v1/common_pb.rb +2 -1
- data/lib/antd/v1/health_pb.rb +1 -1
- data/lib/antd/v1/upload_pb.rb +2 -1
- data/lib/antd/v1/upload_services_pb.rb +4 -2
- data/lib/antd/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ab6786553e76394691c28a2968384dd279738e876ecf961e74a0b7b46904cc0e
|
|
4
|
+
data.tar.gz: a04836fdba38a5457a3cfda27c3adde84bc8175a87dcd1c58e719fb315cc1f0a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: '0806f4881413dd24b52a385319ee23ca30de479dea639b54ef0088bd31f8f0cdba73c0d458843082f697e6a92a3bb4c1f5c34dd77532d38d8032dcb4845f3c78'
|
|
7
|
+
data.tar.gz: 12fffe89716557c9dc2716a99f5f8b39a4958251387050f8828f45ff69628e2350e5aa6dc370f55a89d3abfc06fbb214770bf9cd1c31e516e794fc09daaf9fd4
|
data/README.md
CHANGED
|
@@ -87,7 +87,14 @@ puts "Retrieved: #{data}"
|
|
|
87
87
|
```
|
|
88
88
|
|
|
89
89
|
The `GrpcClient` raises the same `Antd::AntdError` hierarchy as the REST
|
|
90
|
-
client, translating gRPC status codes to the appropriate error subclass
|
|
90
|
+
client, translating gRPC status codes to the appropriate error subclass
|
|
91
|
+
(an `ABORTED` whose status details — `GRPC::BadStatus#details`, the text
|
|
92
|
+
the daemon sent — start with `Partial upload:` becomes
|
|
93
|
+
`Antd::PartialUploadError`, with the chunk counts, `retryable` and
|
|
94
|
+
`retention_known` parsed from that text — see
|
|
95
|
+
[Partial uploads](#partial-uploads); any other
|
|
96
|
+
`ABORTED`, including one that only mentions `Partial upload:` later in its
|
|
97
|
+
text, stays a generic `Antd::AntdError`).
|
|
91
98
|
|
|
92
99
|
> **Note:** Wallet operations (address, balance, approve) and payment_mode are available via REST only.
|
|
93
100
|
|
|
@@ -172,6 +179,82 @@ end
|
|
|
172
179
|
| `TooLargeError` | 413 | Payload too large |
|
|
173
180
|
| `InternalError` | 500 | Server error |
|
|
174
181
|
| `NetworkError` | 502 | Network unreachable |
|
|
182
|
+
| `PartialUploadError` | 502 (`code: "PARTIAL_UPLOAD"`) | Finalize stored some chunks but not all — subclass of `NetworkError` |
|
|
183
|
+
|
|
184
|
+
### Partial uploads
|
|
185
|
+
|
|
186
|
+
A `finalize_upload` / `finalize_merkle_upload` / `finalize_chunk_upload` call
|
|
187
|
+
can fail *after* the external signer has paid: some chunks store, others miss
|
|
188
|
+
quorum after the daemon's own retries. The daemon reports this as HTTP `502`
|
|
189
|
+
with `code: "PARTIAL_UPLOAD"` (gRPC `ABORTED`), and the SDK raises
|
|
190
|
+
`Antd::PartialUploadError` carrying `chunks_stored`, `chunks_failed`,
|
|
191
|
+
`total_chunks`, `retryable` and `retention_known`. The on-chain payment
|
|
192
|
+
persists and the stored chunks stay on the network; what to do next depends
|
|
193
|
+
on what the daemon said about the paid attempt:
|
|
194
|
+
|
|
195
|
+
- **`retryable`** (antd >= 0.14.0; implies `retention_known`) — the daemon
|
|
196
|
+
kept the paid attempt under the same `upload_id`. Call the **same finalize
|
|
197
|
+
method again with the same `upload_id` and payment artefacts** to store the
|
|
198
|
+
remainder against the same payment: no re-prepare, no second signature, no
|
|
199
|
+
double payment. Bound the loop — a persistent failure raises this error on
|
|
200
|
+
every call — so cap the attempts and treat a `chunks_failed` that stops
|
|
201
|
+
shrinking as stuck. The retained attempt expires with the daemon's
|
|
202
|
+
pending-upload TTL.
|
|
203
|
+
- **`retention_known && !retryable`** — the daemon confirmed nothing was
|
|
204
|
+
retained (a merkle finalize with deliberately unpaid batches). Re-prepare
|
|
205
|
+
the same content: already-stored chunks are skipped, so the retry pays only
|
|
206
|
+
for the remainder.
|
|
207
|
+
- **`!retention_known`** — retention is unknown: the error did not say, in a
|
|
208
|
+
form the SDK could read, whether the paid attempt was kept. The daemon may
|
|
209
|
+
still hold it (it records the resume handle before it returns the error).
|
|
210
|
+
Stop automatic recovery, keep the `upload_id` and the original payment
|
|
211
|
+
artefacts (tx hashes, or the merkle winner pool hash), and reconcile before
|
|
212
|
+
re-preparing or paying again. **Never pay again on this signal alone.**
|
|
213
|
+
Daemons older than 0.14.0 never send `retryable`, so their REST partial
|
|
214
|
+
uploads read as unknown.
|
|
215
|
+
|
|
216
|
+
Over REST, `retention_known` is true only when the body's `retryable` is a
|
|
217
|
+
JSON boolean (`true` or `false`); absent, `null` or any other type reads as
|
|
218
|
+
unknown. Over gRPC there is no structured body, so the counts and flags are
|
|
219
|
+
parsed from the status text,
|
|
220
|
+
`Partial upload: <stored>/<total> chunks stored, <failed> failed after retries: <reason> (<hint>)`.
|
|
221
|
+
`retention_known` is true only when the text starts with that counts
|
|
222
|
+
pattern, all three counts parse (each within the daemon's u64 range), and the
|
|
223
|
+
text ends with one of the daemon's two hints: `(paid attempt retained...)`
|
|
224
|
+
sets `retryable`, and `(stored chunks persist; re-prepare the same content...)`
|
|
225
|
+
means the daemon confirmed nothing was retained (daemons older than 0.14.0
|
|
226
|
+
write only this one). If the counts cannot be read, all three are `0` and
|
|
227
|
+
both flags are `false`. Readable counts with a missing, truncated or
|
|
228
|
+
unrecognised hint keep the counts, but both flags stay `false`: retention is
|
|
229
|
+
unknown, so stop and reconcile rather than re-prepare.
|
|
230
|
+
|
|
231
|
+
`PartialUploadError` subclasses `NetworkError` (the 502 mapping), so existing
|
|
232
|
+
`rescue Antd::NetworkError` blocks keep catching it; rescue the subclass first
|
|
233
|
+
to handle it specifically.
|
|
234
|
+
|
|
235
|
+
```ruby
|
|
236
|
+
MAX_ATTEMPTS = 5
|
|
237
|
+
last_failed = nil
|
|
238
|
+
attempt = 0
|
|
239
|
+
begin
|
|
240
|
+
attempt += 1
|
|
241
|
+
result = client.finalize_upload(prep.upload_id, tx_hashes)
|
|
242
|
+
rescue Antd::PartialUploadError => e
|
|
243
|
+
# Not resumable. With retention_known, nothing was retained: re-prepare.
|
|
244
|
+
# Without it, retention is unknown: stop, keep upload_id + tx_hashes and
|
|
245
|
+
# reconcile before re-preparing or paying again.
|
|
246
|
+
raise unless e.retryable
|
|
247
|
+
stuck = !last_failed.nil? && e.chunks_failed >= last_failed
|
|
248
|
+
raise if attempt >= MAX_ATTEMPTS || stuck # bounded: same payment, same upload_id
|
|
249
|
+
last_failed = e.chunks_failed
|
|
250
|
+
sleep(2 * attempt)
|
|
251
|
+
retry
|
|
252
|
+
end
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
See [`docs/external-signer-flow.md` section 6](../docs/external-signer-flow.md#6-retry-a-partial-store--same-upload_id-same-payment)
|
|
256
|
+
for the daemon contract and `examples/07_external_signer.rb` for a
|
|
257
|
+
`finalize_with_retry` helper.
|
|
175
258
|
|
|
176
259
|
## Examples
|
|
177
260
|
|
|
@@ -182,3 +265,4 @@ See the [examples/](examples/) directory:
|
|
|
182
265
|
- `03_chunks.rb` — Chunk put/get
|
|
183
266
|
- `04_files.rb` — File upload and download
|
|
184
267
|
- `06_private_data.rb` — Private data put/get
|
|
268
|
+
- `07_external_signer.rb` — External-signer prepare/pay/finalize with a bounded partial-upload retry
|
data/lib/antd/client.rb
CHANGED
|
@@ -217,6 +217,16 @@ module Antd
|
|
|
217
217
|
# @param tx_hashes [Hash<String, String>] map of quote_hash to tx_hash
|
|
218
218
|
# @return [String] network address of the stored chunk
|
|
219
219
|
# (matches +PrepareChunkResult#address+)
|
|
220
|
+
# @raise [PartialUploadError] when some chunks stored and others did not
|
|
221
|
+
# (HTTP 502, +code: "PARTIAL_UPLOAD"+). The payment persists. If
|
|
222
|
+
# +retryable+, call this method again with the same arguments to store
|
|
223
|
+
# the remainder against the same payment (antd >= 0.14.0). If
|
|
224
|
+
# +retention_known+ but not +retryable+, nothing was retained:
|
|
225
|
+
# re-prepare the same content, which skips stored chunks. If
|
|
226
|
+
# +retention_known+ is false, retention is unknown: stop, keep the
|
|
227
|
+
# upload_id and payment artefacts, and reconcile before re-preparing
|
|
228
|
+
# or paying again. See +PartialUploadError+ and
|
|
229
|
+
# docs/external-signer-flow.md section 6.
|
|
220
230
|
def finalize_chunk_upload(upload_id, tx_hashes)
|
|
221
231
|
j = do_json(:post, "/v1/chunks/finalize", {
|
|
222
232
|
upload_id: upload_id,
|
|
@@ -365,6 +375,16 @@ module Antd
|
|
|
365
375
|
# @param upload_id [String] the upload ID from prepare_upload
|
|
366
376
|
# @param tx_hashes [Hash<String, String>] map of quote_hash to tx_hash
|
|
367
377
|
# @return [FinalizeUploadResult]
|
|
378
|
+
# @raise [PartialUploadError] when some chunks stored and others did not
|
|
379
|
+
# (HTTP 502, +code: "PARTIAL_UPLOAD"+). The payment persists. If
|
|
380
|
+
# +retryable+, call this method again with the same arguments to store
|
|
381
|
+
# the remainder against the same payment (antd >= 0.14.0). If
|
|
382
|
+
# +retention_known+ but not +retryable+, nothing was retained:
|
|
383
|
+
# re-prepare the same content, which skips stored chunks. If
|
|
384
|
+
# +retention_known+ is false, retention is unknown: stop, keep the
|
|
385
|
+
# upload_id and payment artefacts, and reconcile before re-preparing
|
|
386
|
+
# or paying again. See +PartialUploadError+ and
|
|
387
|
+
# docs/external-signer-flow.md section 6.
|
|
368
388
|
def finalize_upload(upload_id, tx_hashes)
|
|
369
389
|
j = do_json(:post, "/v1/upload/finalize", {
|
|
370
390
|
upload_id: upload_id,
|
|
@@ -378,6 +398,16 @@ module Antd
|
|
|
378
398
|
# @param winner_pool_hash [String] hash of the winning pool commitment
|
|
379
399
|
# @param store_data_map [Boolean] whether to store the data map on-network
|
|
380
400
|
# @return [FinalizeUploadResult]
|
|
401
|
+
# @raise [PartialUploadError] when some chunks stored and others did not
|
|
402
|
+
# (HTTP 502, +code: "PARTIAL_UPLOAD"+). The payment persists. If
|
|
403
|
+
# +retryable+, call this method again with the same arguments to store
|
|
404
|
+
# the remainder against the same payment (antd >= 0.14.0). If
|
|
405
|
+
# +retention_known+ but not +retryable+, nothing was retained:
|
|
406
|
+
# re-prepare the same content, which skips stored chunks. If
|
|
407
|
+
# +retention_known+ is false, retention is unknown: stop, keep the
|
|
408
|
+
# upload_id and payment artefacts, and reconcile before re-preparing
|
|
409
|
+
# or paying again. See +PartialUploadError+ and
|
|
410
|
+
# docs/external-signer-flow.md section 6.
|
|
381
411
|
def finalize_merkle_upload(upload_id, winner_pool_hash, store_data_map: false)
|
|
382
412
|
j = do_json(:post, "/v1/upload/finalize", {
|
|
383
413
|
upload_id: upload_id,
|
|
@@ -483,6 +513,10 @@ module Antd
|
|
|
483
513
|
end
|
|
484
514
|
|
|
485
515
|
# Perform a JSON HTTP request and return the parsed response body.
|
|
516
|
+
#
|
|
517
|
+
# A non-2xx response is raised via +Antd.error_for_response+, which maps
|
|
518
|
+
# the body's +code+ / +error+ (and the PARTIAL_UPLOAD counts) onto the
|
|
519
|
+
# typed +AntdError+ hierarchy.
|
|
486
520
|
def do_json(method, path, body = nil)
|
|
487
521
|
uri = build_uri(path)
|
|
488
522
|
http = Net::HTTP.new(uri.host, uri.port)
|
|
@@ -505,14 +539,7 @@ module Antd
|
|
|
505
539
|
code = response.code.to_i
|
|
506
540
|
|
|
507
541
|
unless (200...300).cover?(code)
|
|
508
|
-
|
|
509
|
-
begin
|
|
510
|
-
parsed = JSON.parse(msg)
|
|
511
|
-
msg = parsed["error"] if parsed["error"]
|
|
512
|
-
rescue JSON::ParserError
|
|
513
|
-
# use raw body as message
|
|
514
|
-
end
|
|
515
|
-
raise Antd.error_for_status(code, msg)
|
|
542
|
+
raise Antd.error_for_response(code, response.body)
|
|
516
543
|
end
|
|
517
544
|
|
|
518
545
|
return {} if response.body.nil? || response.body.empty?
|
|
@@ -524,9 +551,9 @@ module Antd
|
|
|
524
551
|
# they arrive. Reuses the same base-URL / timeout / error-mapping plumbing
|
|
525
552
|
# as +do_json+, but never buffers the success body in memory.
|
|
526
553
|
#
|
|
527
|
-
# On a non-2xx response the (short) body is read fully
|
|
528
|
-
# +
|
|
529
|
-
#
|
|
554
|
+
# On a non-2xx response the (short) body is read fully and raised via
|
|
555
|
+
# +Antd.error_for_response+ — mirroring +do_json+. On 2xx, chunks are
|
|
556
|
+
# streamed straight to the block.
|
|
530
557
|
def do_stream(method, path, body = nil)
|
|
531
558
|
uri = build_uri(path)
|
|
532
559
|
http = Net::HTTP.new(uri.host, uri.port)
|
|
@@ -550,14 +577,7 @@ module Antd
|
|
|
550
577
|
code = response.code.to_i
|
|
551
578
|
|
|
552
579
|
unless (200...300).cover?(code)
|
|
553
|
-
|
|
554
|
-
begin
|
|
555
|
-
parsed = JSON.parse(msg)
|
|
556
|
-
msg = parsed["error"] if parsed["error"]
|
|
557
|
-
rescue JSON::ParserError
|
|
558
|
-
# use raw body as message
|
|
559
|
-
end
|
|
560
|
-
raise Antd.error_for_status(code, msg)
|
|
580
|
+
raise Antd.error_for_response(code, response.body)
|
|
561
581
|
end
|
|
562
582
|
|
|
563
583
|
response.read_body do |chunk|
|
|
@@ -599,14 +619,7 @@ module Antd
|
|
|
599
619
|
code = response.code.to_i
|
|
600
620
|
|
|
601
621
|
unless (200...300).cover?(code)
|
|
602
|
-
|
|
603
|
-
begin
|
|
604
|
-
parsed = JSON.parse(msg)
|
|
605
|
-
msg = parsed["error"] if parsed["error"]
|
|
606
|
-
rescue JSON::ParserError
|
|
607
|
-
# use raw body as message
|
|
608
|
-
end
|
|
609
|
-
raise Antd.error_for_status(code, msg)
|
|
622
|
+
raise Antd.error_for_response(code, response.body)
|
|
610
623
|
end
|
|
611
624
|
|
|
612
625
|
buffer = +""
|
data/lib/antd/errors.rb
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "json"
|
|
4
|
+
|
|
3
5
|
module Antd
|
|
4
6
|
# Base error type for all antd errors.
|
|
5
7
|
class AntdError < StandardError
|
|
@@ -56,6 +58,228 @@ module Antd
|
|
|
56
58
|
def initialize(message) = super(message, status_code: 503)
|
|
57
59
|
end
|
|
58
60
|
|
|
61
|
+
# A finalize stored some chunks while others remained unstored after the
|
|
62
|
+
# daemon's retries (HTTP 502 with +code: "PARTIAL_UPLOAD"+; gRPC ABORTED).
|
|
63
|
+
# The on-chain payment persists and the stored chunks stay on the network.
|
|
64
|
+
# How to finish the upload depends on +retryable+ and +retention_known+:
|
|
65
|
+
#
|
|
66
|
+
# - +retryable+ (antd >= 0.14.0; implies +retention_known+): the daemon kept
|
|
67
|
+
# the paid attempt (payment proofs + unstored chunks) under the same
|
|
68
|
+
# +upload_id+. Call the same +finalize_*+ method again with the same
|
|
69
|
+
# +upload_id+ and payment artefacts to store the remainder against the
|
|
70
|
+
# same payment -- no re-prepare, no second signature, no double payment.
|
|
71
|
+
# Bound the loop: a persistent failure raises this error on every call, so
|
|
72
|
+
# cap the attempts and treat a +chunks_failed+ that stops shrinking as
|
|
73
|
+
# stuck. The retained attempt expires with the daemon's pending-upload
|
|
74
|
+
# TTL.
|
|
75
|
+
# - +retention_known+ and not +retryable+: the daemon confirmed nothing was
|
|
76
|
+
# retained (a merkle finalize with deliberately unpaid batches).
|
|
77
|
+
# Re-preparing the same content skips already-stored chunks, so a retry
|
|
78
|
+
# pays only for the missing remainder.
|
|
79
|
+
# - not +retention_known+: retention is unknown. The error did not say, in
|
|
80
|
+
# a form this SDK could read, whether the paid attempt was kept, and the
|
|
81
|
+
# daemon may still hold it: it records the resume handle before it
|
|
82
|
+
# returns the error. Stop automatic recovery, keep the +upload_id+ and the
|
|
83
|
+
# original payment artefacts (tx hashes, or the merkle winner pool hash),
|
|
84
|
+
# and reconcile before re-preparing or paying again. Never pay again on
|
|
85
|
+
# this signal alone. Daemons older than 0.14.0 never send +retryable+, so
|
|
86
|
+
# their REST partial uploads read as unknown.
|
|
87
|
+
#
|
|
88
|
+
# Over REST the counts and flags come from the structured error body; a
|
|
89
|
+
# count of the wrong JSON type reads as 0, and +retention_known+ is true
|
|
90
|
+
# only when the body's +retryable+ is a JSON boolean. Over gRPC they are
|
|
91
|
+
# parsed best-effort from the status details ("Partial upload: S/T chunks
|
|
92
|
+
# stored, F failed after retries: <reason> (<hint>)"); only an ABORTED
|
|
93
|
+
# whose details start with "Partial upload:" is a partial upload.
|
|
94
|
+
# +retention_known+ is true there only when the details start with the
|
|
95
|
+
# counts, all three parse, and the details end with one of the daemon's two
|
|
96
|
+
# hints: "(paid attempt retained...)" sets +retryable+, and "(stored chunks
|
|
97
|
+
# persist; re-prepare the same content...)" means the daemon confirmed
|
|
98
|
+
# nothing was retained (daemons older than 0.14.0 write only this one).
|
|
99
|
+
# Counts that do not parse leave all three zero and both flags false.
|
|
100
|
+
# Readable counts with a missing, truncated or unrecognised hint keep the
|
|
101
|
+
# counts, but both flags stay false: retention unknown, not "nothing
|
|
102
|
+
# retained".
|
|
103
|
+
#
|
|
104
|
+
# Subclasses +NetworkError+ because the daemon reports it as a 502: existing
|
|
105
|
+
# +rescue Antd::NetworkError+ blocks keep catching it, and +status_code+ is
|
|
106
|
+
# 502 on both transports. Rescue +PartialUploadError+ first to handle it
|
|
107
|
+
# specifically. See docs/external-signer-flow.md section 6.
|
|
108
|
+
class PartialUploadError < NetworkError
|
|
109
|
+
attr_reader :chunks_stored, :chunks_failed, :total_chunks, :retryable, :retention_known
|
|
110
|
+
|
|
111
|
+
# @param message [String]
|
|
112
|
+
# @param chunks_stored [Integer] chunks confirmed stored on the network
|
|
113
|
+
# @param chunks_failed [Integer] chunks still unstored after retries
|
|
114
|
+
# @param total_chunks [Integer] chunks in the upload
|
|
115
|
+
# @param retryable [Boolean] whether the daemon retained the paid attempt
|
|
116
|
+
# @param retention_known [Boolean] whether the daemon said, in a form this
|
|
117
|
+
# SDK could read, whether it retained the paid attempt. +retryable+
|
|
118
|
+
# implies it: +retryable: true+ always yields +retention_known == true+.
|
|
119
|
+
def initialize(message, chunks_stored: 0, chunks_failed: 0, total_chunks: 0, retryable: false,
|
|
120
|
+
retention_known: false)
|
|
121
|
+
@chunks_stored = chunks_stored
|
|
122
|
+
@chunks_failed = chunks_failed
|
|
123
|
+
@total_chunks = total_chunks
|
|
124
|
+
@retryable = retryable
|
|
125
|
+
@retention_known = (retention_known || retryable) ? true : false
|
|
126
|
+
super(message)
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
alias retryable? retryable
|
|
130
|
+
alias retention_known? retention_known
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# Fixed text every PARTIAL_UPLOAD message from the daemon opens with. Over
|
|
134
|
+
# gRPC the status carries no structured code, so an ABORTED status is a
|
|
135
|
+
# partial upload only when its details start with this prefix.
|
|
136
|
+
PARTIAL_UPLOAD_PREFIX = "Partial upload:"
|
|
137
|
+
|
|
138
|
+
# Fixed prefix of the daemon's PARTIAL_UPLOAD message:
|
|
139
|
+
# "Partial upload: <stored>/<total> chunks stored, <failed> failed".
|
|
140
|
+
# Anchored with +\A+ (start of input; +^+ would also match after a
|
|
141
|
+
# newline), so counts quoted later in a garbled message are never read.
|
|
142
|
+
PARTIAL_UPLOAD_COUNTS = %r{\APartial upload: (\d+)/(\d+) chunks stored, (\d+) failed}
|
|
143
|
+
|
|
144
|
+
# The daemon closes every PARTIAL_UPLOAD message with one of two
|
|
145
|
+
# parenthesised hints (partial_upload_hint in antd/src/error.rs). This one
|
|
146
|
+
# opens the hint when it kept the paid attempt for a same-upload_id retry.
|
|
147
|
+
PARTIAL_UPLOAD_RETAINED_HINT = "paid attempt retained"
|
|
148
|
+
|
|
149
|
+
# This one opens the hint when it did not. Daemons older than 0.14.0 write
|
|
150
|
+
# only this one.
|
|
151
|
+
PARTIAL_UPLOAD_NOT_RETAINED_HINT = "stored chunks persist; re-prepare the same content"
|
|
152
|
+
private_constant :PARTIAL_UPLOAD_NOT_RETAINED_HINT
|
|
153
|
+
|
|
154
|
+
# The hint that closes the message: "(<hint>...)" at the very end. +\z+ is
|
|
155
|
+
# the end of the input; Ruby's +$+ is the end of a LINE and +\Z+ allows a
|
|
156
|
+
# trailing newline. A hint quoted inside the failure reason, a truncated
|
|
157
|
+
# or unclosed tail, or any text after the hint does not match.
|
|
158
|
+
PARTIAL_UPLOAD_RETENTION_TAIL =
|
|
159
|
+
/\((#{Regexp.union(PARTIAL_UPLOAD_RETAINED_HINT, PARTIAL_UPLOAD_NOT_RETAINED_HINT).source})[^()]*\)\z/
|
|
160
|
+
private_constant :PARTIAL_UPLOAD_RETENTION_TAIL
|
|
161
|
+
|
|
162
|
+
# Largest count the daemon can send (its counts are u64). Ruby integers are
|
|
163
|
+
# unbounded, so a larger digit run is treated as a failed conversion.
|
|
164
|
+
PARTIAL_UPLOAD_COUNT_MAX = 18_446_744_073_709_551_615
|
|
165
|
+
private_constant :PARTIAL_UPLOAD_COUNT_MAX
|
|
166
|
+
|
|
167
|
+
# Whether a gRPC status's details are the daemon's PARTIAL_UPLOAD message.
|
|
168
|
+
# Anchored: the details must start with +PARTIAL_UPLOAD_PREFIX+. A status
|
|
169
|
+
# that merely quotes "Partial upload:" further into its text (an upstream
|
|
170
|
+
# error wrapping one, say) is not a partial upload and must not select the
|
|
171
|
+
# paid-attempt recovery path with zero counts.
|
|
172
|
+
#
|
|
173
|
+
# Pass +GRPC::BadStatus#details+ -- the status message exactly as the
|
|
174
|
+
# daemon sent it -- not +#message+, which grpc-ruby decorates as
|
|
175
|
+
# "<code>:<details>" ("10:Partial upload: ...") and so never starts with
|
|
176
|
+
# the prefix.
|
|
177
|
+
#
|
|
178
|
+
# @param details [String, nil] gRPC status details
|
|
179
|
+
# @return [Boolean]
|
|
180
|
+
def self.partial_upload_message?(details)
|
|
181
|
+
details.to_s.start_with?(PARTIAL_UPLOAD_PREFIX)
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
# Recovers the chunk counts and the retention flags from a PARTIAL_UPLOAD
|
|
185
|
+
# message (over gRPC, the status details). Used for gRPC, where the status
|
|
186
|
+
# carries no structured detail; REST callers get the body fields instead.
|
|
187
|
+
#
|
|
188
|
+
# Conservative: +retention_known+ is true only when the message starts
|
|
189
|
+
# with the counts pattern ("Partial upload: <stored>/<total> chunks
|
|
190
|
+
# stored, <failed> failed"), all three counts converted (each at most
|
|
191
|
+
# u64::MAX, the daemon's count type), and the message ends with one of the
|
|
192
|
+
# daemon's two hints, "(paid attempt retained...)" or "(stored chunks
|
|
193
|
+
# persist; re-prepare the same content...)"; +retryable+ is then true only
|
|
194
|
+
# for the first. On a prefix or pattern miss, or a count out of range, all
|
|
195
|
+
# three counts are 0 and both flags are false. Readable counts with a
|
|
196
|
+
# missing, truncated or unrecognised tail, or text after it, keep the
|
|
197
|
+
# counts but leave both flags false: the daemon's answer on retention was
|
|
198
|
+
# not read, so retention is unknown, never "nothing retained". A message
|
|
199
|
+
# the parser cannot fully read never selects the same-upload_id retry, and
|
|
200
|
+
# never reads as confirmed non-retention.
|
|
201
|
+
#
|
|
202
|
+
# @param message [String]
|
|
203
|
+
# @return [Hash] +:chunks_stored+, +:chunks_failed+, +:total_chunks+,
|
|
204
|
+
# +:retryable+, +:retention_known+ -- splat into +PartialUploadError.new+
|
|
205
|
+
def self.parse_partial_upload_message(message)
|
|
206
|
+
text = message.to_s
|
|
207
|
+
m = partial_upload_message?(text) && PARTIAL_UPLOAD_COUNTS.match(text)
|
|
208
|
+
# The groups are ASCII digit runs, so #to_i is exact; only the range can fail.
|
|
209
|
+
stored, total, failed = m && [m[1], m[2], m[3]].map(&:to_i)
|
|
210
|
+
unless m && [stored, total, failed].all? { |n| n <= PARTIAL_UPLOAD_COUNT_MAX }
|
|
211
|
+
return { chunks_stored: 0, chunks_failed: 0, total_chunks: 0, retryable: false, retention_known: false }
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
# Only the hint that closes the message is the daemon's answer.
|
|
215
|
+
tail = PARTIAL_UPLOAD_RETENTION_TAIL.match(text)
|
|
216
|
+
{
|
|
217
|
+
chunks_stored: stored,
|
|
218
|
+
chunks_failed: failed,
|
|
219
|
+
total_chunks: total,
|
|
220
|
+
retryable: !tail.nil? && tail[1] == PARTIAL_UPLOAD_RETAINED_HINT,
|
|
221
|
+
retention_known: !tail.nil?
|
|
222
|
+
}
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
# Maps a non-2xx REST response onto a typed error, preferring the body's
|
|
226
|
+
# machine-readable +code+ over the bare HTTP status where they diverge:
|
|
227
|
+
# +PARTIAL_UPLOAD+ arrives as a 502 that would otherwise read as a generic
|
|
228
|
+
# +NetworkError+. Every other code keeps the status-based mapping of
|
|
229
|
+
# +error_for_status+. A JSON object body's +error+ field becomes the
|
|
230
|
+
# message when it is a string; otherwise (non-JSON body, a JSON value that
|
|
231
|
+
# is not an object, a non-string +error+) the raw body is the message.
|
|
232
|
+
#
|
|
233
|
+
# Never raises on a malformed body: every field is type-checked, not
|
|
234
|
+
# coerced. Only a +code+ that is exactly the string "PARTIAL_UPLOAD"
|
|
235
|
+
# selects +PartialUploadError+; a count that is not a non-negative JSON
|
|
236
|
+
# integer reads as 0; +retryable+ is true only for JSON +true+; and
|
|
237
|
+
# +retention_known+ is true only when +retryable+ is a JSON boolean (absent
|
|
238
|
+
# on daemons < 0.14.0, +null+ or any other type reads as unknown).
|
|
239
|
+
#
|
|
240
|
+
# @param code [Integer] HTTP status
|
|
241
|
+
# @param body [String, nil] raw response body
|
|
242
|
+
# @return [AntdError]
|
|
243
|
+
def self.error_for_response(code, body)
|
|
244
|
+
message = body.to_s
|
|
245
|
+
parsed = begin
|
|
246
|
+
JSON.parse(message)
|
|
247
|
+
rescue JSON::ParserError
|
|
248
|
+
nil # use raw body as message
|
|
249
|
+
end
|
|
250
|
+
parsed = nil unless parsed.is_a?(Hash)
|
|
251
|
+
|
|
252
|
+
if parsed
|
|
253
|
+
message = parsed["error"] if parsed["error"].is_a?(String)
|
|
254
|
+
if parsed["code"] == "PARTIAL_UPLOAD"
|
|
255
|
+
return PartialUploadError.new(
|
|
256
|
+
message,
|
|
257
|
+
chunks_stored: body_count(parsed["chunks_stored"]),
|
|
258
|
+
chunks_failed: body_count(parsed["chunks_failed"]),
|
|
259
|
+
total_chunks: body_count(parsed["total_chunks"]),
|
|
260
|
+
retryable: parsed["retryable"] == true,
|
|
261
|
+
# Known only when the daemon sent the flag as a JSON boolean. Absent
|
|
262
|
+
# (daemons < 0.14.0), null or any other type -> unknown: the daemon
|
|
263
|
+
# may still hold the paid attempt, so this is not a re-prepare signal.
|
|
264
|
+
retention_known: [true, false].include?(parsed["retryable"])
|
|
265
|
+
)
|
|
266
|
+
end
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
error_for_status(code, message)
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
# A chunk count from a PARTIAL_UPLOAD body: a non-negative JSON integer is
|
|
273
|
+
# taken as is; anything else (absent, null, string, float, boolean, array,
|
|
274
|
+
# object, negative) reads as 0 rather than raising or being coerced.
|
|
275
|
+
#
|
|
276
|
+
# @param value [Object] parsed JSON value
|
|
277
|
+
# @return [Integer]
|
|
278
|
+
def self.body_count(value)
|
|
279
|
+
value.is_a?(Integer) && value >= 0 ? value : 0
|
|
280
|
+
end
|
|
281
|
+
private_class_method :body_count
|
|
282
|
+
|
|
59
283
|
# Returns the appropriate error type for an HTTP status code.
|
|
60
284
|
def self.error_for_status(code, message)
|
|
61
285
|
case code
|
data/lib/antd/grpc_client.rb
CHANGED
|
@@ -324,6 +324,16 @@ module Antd
|
|
|
324
324
|
# @param upload_id [String]
|
|
325
325
|
# @param tx_hashes [Hash<String, String>]
|
|
326
326
|
# @return [String] hex chunk address
|
|
327
|
+
# @raise [PartialUploadError] when some chunks stored and others did not
|
|
328
|
+
# (gRPC ABORTED, details prefixed +Partial upload:+). The payment
|
|
329
|
+
# persists. If +retryable+, call this method again with the same
|
|
330
|
+
# arguments to store the remainder against the same payment
|
|
331
|
+
# (antd >= 0.14.0). If +retention_known+ but not +retryable+, nothing
|
|
332
|
+
# was retained: re-prepare the same content, which skips stored chunks.
|
|
333
|
+
# If +retention_known+ is false, retention is unknown: stop, keep the
|
|
334
|
+
# upload_id and payment artefacts, and reconcile before re-preparing or
|
|
335
|
+
# paying again. See +PartialUploadError+ and
|
|
336
|
+
# docs/external-signer-flow.md section 6.
|
|
327
337
|
def finalize_chunk_upload(upload_id, tx_hashes)
|
|
328
338
|
req = Antd::V1::FinalizeChunkRequest.new(
|
|
329
339
|
upload_id: upload_id,
|
|
@@ -378,6 +388,16 @@ module Antd
|
|
|
378
388
|
# @param upload_id [String]
|
|
379
389
|
# @param tx_hashes [Hash<String, String>]
|
|
380
390
|
# @return [FinalizeUploadResult]
|
|
391
|
+
# @raise [PartialUploadError] when some chunks stored and others did not
|
|
392
|
+
# (gRPC ABORTED, details prefixed +Partial upload:+). The payment
|
|
393
|
+
# persists. If +retryable+, call this method again with the same
|
|
394
|
+
# arguments to store the remainder against the same payment
|
|
395
|
+
# (antd >= 0.14.0). If +retention_known+ but not +retryable+, nothing
|
|
396
|
+
# was retained: re-prepare the same content, which skips stored chunks.
|
|
397
|
+
# If +retention_known+ is false, retention is unknown: stop, keep the
|
|
398
|
+
# upload_id and payment artefacts, and reconcile before re-preparing or
|
|
399
|
+
# paying again. See +PartialUploadError+ and
|
|
400
|
+
# docs/external-signer-flow.md section 6.
|
|
381
401
|
def finalize_upload(upload_id, tx_hashes)
|
|
382
402
|
req = Antd::V1::FinalizeUploadRequest.new(
|
|
383
403
|
upload_id: upload_id,
|
|
@@ -399,6 +419,16 @@ module Antd
|
|
|
399
419
|
# @param winner_pool_hash [String]
|
|
400
420
|
# @param store_data_map [Boolean]
|
|
401
421
|
# @return [FinalizeUploadResult]
|
|
422
|
+
# @raise [PartialUploadError] when some chunks stored and others did not
|
|
423
|
+
# (gRPC ABORTED, details prefixed +Partial upload:+). The payment
|
|
424
|
+
# persists. If +retryable+, call this method again with the same
|
|
425
|
+
# arguments to store the remainder against the same payment
|
|
426
|
+
# (antd >= 0.14.0). If +retention_known+ but not +retryable+, nothing
|
|
427
|
+
# was retained: re-prepare the same content, which skips stored chunks.
|
|
428
|
+
# If +retention_known+ is false, retention is unknown: stop, keep the
|
|
429
|
+
# upload_id and payment artefacts, and reconcile before re-preparing or
|
|
430
|
+
# paying again. See +PartialUploadError+ and
|
|
431
|
+
# docs/external-signer-flow.md section 6.
|
|
402
432
|
def finalize_merkle_upload(upload_id, winner_pool_hash, store_data_map: false)
|
|
403
433
|
req = Antd::V1::FinalizeUploadRequest.new(
|
|
404
434
|
upload_id: upload_id,
|
|
@@ -520,7 +550,11 @@ module Antd
|
|
|
520
550
|
payment_type: resp.payment_type,
|
|
521
551
|
depth: is_merkle ? resp.depth : nil,
|
|
522
552
|
pool_commitments: pool_commitments,
|
|
523
|
-
merkle_payment_timestamp: is_merkle ? resp.merkle_payment_timestamp.to_i : nil
|
|
553
|
+
merkle_payment_timestamp: is_merkle ? resp.merkle_payment_timestamp.to_i : nil,
|
|
554
|
+
# Already-stored preflight (parity with REST): the external signer
|
|
555
|
+
# pays for total_chunks - already_stored_count chunks.
|
|
556
|
+
total_chunks: resp.total_chunks,
|
|
557
|
+
already_stored_count: resp.already_stored_count
|
|
524
558
|
)
|
|
525
559
|
end
|
|
526
560
|
|
|
@@ -542,6 +576,24 @@ module Antd
|
|
|
542
576
|
raise NetworkError, e.message
|
|
543
577
|
rescue GRPC::FailedPrecondition => e
|
|
544
578
|
raise PaymentError, e.message
|
|
579
|
+
rescue GRPC::Aborted => e
|
|
580
|
+
# PARTIAL_UPLOAD: some chunks stored, some still unstored after
|
|
581
|
+
# retries. The daemon's status message always opens with "Partial
|
|
582
|
+
# upload:", so only an ABORTED whose details *start* with it becomes
|
|
583
|
+
# the typed error. Any other ABORTED -- including one that merely
|
|
584
|
+
# quotes the marker further in -- keeps the generic mapping instead of
|
|
585
|
+
# masquerading as a partial upload with zero counts. Gate and parse on
|
|
586
|
+
# +e.details+ (the message as the daemon sent it), not +e.message+,
|
|
587
|
+
# which grpc-ruby decorates as "10:<details>". The counts and the
|
|
588
|
+
# daemon's closing retention hint ride that text over gRPC (no
|
|
589
|
+
# structured detail yet), so parse them best-effort to match the REST
|
|
590
|
+
# client's typed error: retention is known only when the counts parse
|
|
591
|
+
# and the text ends with one of the daemon's two hints (see
|
|
592
|
+
# Antd.parse_partial_upload_message). The raised message stays
|
|
593
|
+
# +e.message+, like every other branch.
|
|
594
|
+
raise AntdError.new(e.message, status_code: e.code) unless Antd.partial_upload_message?(e.details)
|
|
595
|
+
|
|
596
|
+
raise PartialUploadError.new(e.message, **Antd.parse_partial_upload_message(e.details))
|
|
545
597
|
rescue GRPC::BadStatus => e
|
|
546
598
|
raise AntdError.new(e.message, status_code: e.code)
|
|
547
599
|
end
|
data/lib/antd/v1/chunks_pb.rb
CHANGED
|
@@ -7,7 +7,7 @@ require 'google/protobuf'
|
|
|
7
7
|
require 'antd/v1/common_pb'
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
descriptor_data = "\n\x14\x61ntd/v1/chunks.proto\x12\x07\x61ntd.v1\x1a\x14\x61ntd/v1/common.proto\"\"\n\x0fGetChunkRequest\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\t\" \n\x10GetChunkResponse\x12\x0c\n\x04\x64\x61ta\x18\x01 \x01(\x0c\"\x1f\n\x0fPutChunkRequest\x12\x0c\n\x04\x64\x61ta\x18\x01 \x01(\x0c\"@\n\x10PutChunkResponse\x12\x1b\n\x04\x63ost\x18\x01 \x01(\x0b\x32\r.antd.v1.Cost\x12\x0f\n\x07\x61\x64\x64ress\x18\x02 \x01(\t\"
|
|
10
|
+
descriptor_data = "\n\x14\x61ntd/v1/chunks.proto\x12\x07\x61ntd.v1\x1a\x14\x61ntd/v1/common.proto\"\"\n\x0fGetChunkRequest\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\t\" \n\x10GetChunkResponse\x12\x0c\n\x04\x64\x61ta\x18\x01 \x01(\x0c\"\x1f\n\x0fPutChunkRequest\x12\x0c\n\x04\x64\x61ta\x18\x01 \x01(\x0c\"@\n\x10PutChunkResponse\x12\x1b\n\x04\x63ost\x18\x01 \x01(\x0b\x32\r.antd.v1.Cost\x12\x0f\n\x07\x61\x64\x64ress\x18\x02 \x01(\t\"B\n\x13PrepareChunkRequest\x12\x0c\n\x04\x64\x61ta\x18\x01 \x01(\x0c\x12\x1d\n\x15include_signed_quotes\x18\x02 \x01(\x08\"\xa8\x02\n\x14PrepareChunkResponse\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\t\x12\x16\n\x0e\x61lready_stored\x18\x02 \x01(\x08\x12\x11\n\tupload_id\x18\x03 \x01(\t\x12\x14\n\x0cpayment_type\x18\x04 \x01(\t\x12\'\n\x08payments\x18\x05 \x03(\x0b\x32\x15.antd.v1.PaymentEntry\x12\x14\n\x0ctotal_amount\x18\x06 \x01(\t\x12\x1d\n\x15payment_vault_address\x18\x07 \x01(\t\x12\x1d\n\x15payment_token_address\x18\x08 \x01(\t\x12\x0f\n\x07rpc_url\x18\t \x01(\t\x12\x30\n\rsigned_quotes\x18\n \x03(\x0b\x32\x19.antd.v1.SignedQuoteEntry\"\x9a\x01\n\x14\x46inalizeChunkRequest\x12\x11\n\tupload_id\x18\x01 \x01(\t\x12>\n\ttx_hashes\x18\x02 \x03(\x0b\x32+.antd.v1.FinalizeChunkRequest.TxHashesEntry\x1a/\n\rTxHashesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"(\n\x15\x46inalizeChunkResponse\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\t2\xa3\x02\n\x0c\x43hunkService\x12:\n\x03Get\x12\x18.antd.v1.GetChunkRequest\x1a\x19.antd.v1.GetChunkResponse\x12:\n\x03Put\x12\x18.antd.v1.PutChunkRequest\x1a\x19.antd.v1.PutChunkResponse\x12K\n\x0cPrepareChunk\x12\x1c.antd.v1.PrepareChunkRequest\x1a\x1d.antd.v1.PrepareChunkResponse\x12N\n\rFinalizeChunk\x12\x1d.antd.v1.FinalizeChunkRequest\x1a\x1e.antd.v1.FinalizeChunkResponseBDZ8github.com/WithAutonomi/ant-sdk/antd-go/proto/antd/v1;v1\xaa\x02\x07\x41ntd.V1b\x06proto3"
|
|
11
11
|
|
|
12
12
|
pool = ::Google::Protobuf::DescriptorPool.generated_pool
|
|
13
13
|
pool.add_serialized_file(descriptor_data)
|
data/lib/antd/v1/common_pb.rb
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
require 'google/protobuf'
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
descriptor_data = "\n\x14\x61ntd/v1/common.proto\x12\x07\x61ntd.v1\"y\n\x04\x43ost\x12\x13\n\x0b\x61tto_tokens\x18\x01 \x01(\t\x12\x11\n\tfile_size\x18\x02 \x01(\x04\x12\x13\n\x0b\x63hunk_count\x18\x03 \x01(\r\x12\x1e\n\x16\x65stimated_gas_cost_wei\x18\x04 \x01(\t\x12\x14\n\x0cpayment_mode\x18\x05 \x01(\t\"\x16\n\x07\x41\x64\x64ress\x12\x0b\n\x03hex\x18\x01 \x01(\t\"\x1d\n\x0ePublicKeyProto\x12\x0b\n\x03hex\x18\x01 \x01(\t\"\x1d\n\x0eSecretKeyProto\x12\x0b\n\x03hex\x18\x01 \x01(\t\"K\n\x0cPaymentEntry\x12\x12\n\nquote_hash\x18\x01 \x01(\t\x12\x17\n\x0frewards_address\x18\x02 \x01(\t\x12\x0e\n\x06\x61mount\x18\x03 \x01(\
|
|
8
|
+
descriptor_data = "\n\x14\x61ntd/v1/common.proto\x12\x07\x61ntd.v1\"y\n\x04\x43ost\x12\x13\n\x0b\x61tto_tokens\x18\x01 \x01(\t\x12\x11\n\tfile_size\x18\x02 \x01(\x04\x12\x13\n\x0b\x63hunk_count\x18\x03 \x01(\r\x12\x1e\n\x16\x65stimated_gas_cost_wei\x18\x04 \x01(\t\x12\x14\n\x0cpayment_mode\x18\x05 \x01(\t\"\x16\n\x07\x41\x64\x64ress\x12\x0b\n\x03hex\x18\x01 \x01(\t\"\x1d\n\x0ePublicKeyProto\x12\x0b\n\x03hex\x18\x01 \x01(\t\"\x1d\n\x0eSecretKeyProto\x12\x0b\n\x03hex\x18\x01 \x01(\t\"K\n\x0cPaymentEntry\x12\x12\n\nquote_hash\x18\x01 \x01(\t\x12\x17\n\x0frewards_address\x18\x02 \x01(\t\x12\x0e\n\x06\x61mount\x18\x03 \x01(\t\"Q\n\x10SignedQuoteEntry\x12\x12\n\nquote_hash\x18\x01 \x01(\t\x12\r\n\x05quote\x18\x02 \x01(\x0c\x12\x1a\n\x12\x63ommitment_sidecar\x18\x03 \x01(\x0c\x42\x44Z8github.com/WithAutonomi/ant-sdk/antd-go/proto/antd/v1;v1\xaa\x02\x07\x41ntd.V1b\x06proto3"
|
|
9
9
|
|
|
10
10
|
pool = ::Google::Protobuf::DescriptorPool.generated_pool
|
|
11
11
|
pool.add_serialized_file(descriptor_data)
|
|
@@ -17,5 +17,6 @@ module Antd
|
|
|
17
17
|
PublicKeyProto = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("antd.v1.PublicKeyProto").msgclass
|
|
18
18
|
SecretKeyProto = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("antd.v1.SecretKeyProto").msgclass
|
|
19
19
|
PaymentEntry = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("antd.v1.PaymentEntry").msgclass
|
|
20
|
+
SignedQuoteEntry = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("antd.v1.SignedQuoteEntry").msgclass
|
|
20
21
|
end
|
|
21
22
|
end
|
data/lib/antd/v1/health_pb.rb
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
require 'google/protobuf'
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
descriptor_data = "\n\x14\x61ntd/v1/health.proto\x12\x07\x61ntd.v1\"\x14\n\x12HealthCheckRequest\"\
|
|
8
|
+
descriptor_data = "\n\x14\x61ntd/v1/health.proto\x12\x07\x61ntd.v1\"\x14\n\x12HealthCheckRequest\"\xf1\x02\n\x13HealthCheckResponse\x12\x0e\n\x06status\x18\x01 \x01(\t\x12\x0f\n\x07network\x18\x02 \x01(\t\x12\x0f\n\x07version\x18\x03 \x01(\t\x12\x13\n\x0b\x65vm_network\x18\x04 \x01(\t\x12\x16\n\x0euptime_seconds\x18\x05 \x01(\x04\x12\x14\n\x0c\x62uild_commit\x18\x06 \x01(\t\x12\x1d\n\x15payment_token_address\x18\x07 \x01(\t\x12\x1d\n\x15payment_vault_address\x18\x08 \x01(\t\x12\x13\n\x0bwrite_ready\x18\t \x01(\x08\x12\x17\n\x0f\x63onnected_peers\x18\n \x01(\r\x12\x1a\n\x12routing_table_size\x18\x0b \x01(\r\x12\x1d\n\x15rebootstrap_threshold\x18\x0c \x01(\r\x12#\n\x16last_store_ok_secs_ago\x18\r \x01(\x04H\x00\x88\x01\x01\x42\x19\n\x17_last_store_ok_secs_ago2S\n\rHealthService\x12\x42\n\x05\x43heck\x12\x1b.antd.v1.HealthCheckRequest\x1a\x1c.antd.v1.HealthCheckResponseBDZ8github.com/WithAutonomi/ant-sdk/antd-go/proto/antd/v1;v1\xaa\x02\x07\x41ntd.V1b\x06proto3"
|
|
9
9
|
|
|
10
10
|
pool = ::Google::Protobuf::DescriptorPool.generated_pool
|
|
11
11
|
pool.add_serialized_file(descriptor_data)
|
data/lib/antd/v1/upload_pb.rb
CHANGED
|
@@ -7,7 +7,7 @@ require 'google/protobuf'
|
|
|
7
7
|
require 'antd/v1/common_pb'
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
descriptor_data = "\n\x14\x61ntd/v1/upload.proto\x12\x07\x61ntd.v1\x1a\x14\x61ntd/v1/common.proto\"
|
|
10
|
+
descriptor_data = "\n\x14\x61ntd/v1/upload.proto\x12\x07\x61ntd.v1\x1a\x14\x61ntd/v1/common.proto\"[\n\x18PrepareFileUploadRequest\x12\x0c\n\x04path\x18\x01 \x01(\t\x12\x12\n\nvisibility\x18\x02 \x01(\t\x12\x1d\n\x15include_signed_quotes\x18\x03 \x01(\x08\"[\n\x18PrepareDataUploadRequest\x12\x0c\n\x04\x64\x61ta\x18\x01 \x01(\x0c\x12\x12\n\nvisibility\x18\x02 \x01(\t\x12\x1d\n\x15include_signed_quotes\x18\x03 \x01(\x08\"\xd0\x03\n\x15PrepareUploadResponse\x12\x11\n\tupload_id\x18\x01 \x01(\t\x12\x14\n\x0cpayment_type\x18\x02 \x01(\t\x12\'\n\x08payments\x18\x03 \x03(\x0b\x32\x15.antd.v1.PaymentEntry\x12\r\n\x05\x64\x65pth\x18\x04 \x01(\r\x12\x36\n\x10pool_commitments\x18\x05 \x03(\x0b\x32\x1c.antd.v1.PoolCommitmentEntry\x12 \n\x18merkle_payment_timestamp\x18\x06 \x01(\x04\x12\x31\n\x0emerkle_batches\x18\x0b \x03(\x0b\x32\x19.antd.v1.MerkleBatchEntry\x12\x14\n\x0ctotal_amount\x18\x07 \x01(\t\x12\x1d\n\x15payment_vault_address\x18\x08 \x01(\t\x12\x1d\n\x15payment_token_address\x18\t \x01(\t\x12\x0f\n\x07rpc_url\x18\n \x01(\t\x12\x30\n\rsigned_quotes\x18\x0c \x03(\x0b\x32\x19.antd.v1.SignedQuoteEntry\x12\x14\n\x0ctotal_chunks\x18\r \x01(\x04\x12\x1c\n\x14\x61lready_stored_count\x18\x0e \x01(\x04\"{\n\x10MerkleBatchEntry\x12\r\n\x05\x64\x65pth\x18\x01 \x01(\r\x12\x36\n\x10pool_commitments\x18\x02 \x03(\x0b\x32\x1c.antd.v1.PoolCommitmentEntry\x12 \n\x18merkle_payment_timestamp\x18\x03 \x01(\x04\"Y\n\x13PoolCommitmentEntry\x12\x11\n\tpool_hash\x18\x01 \x01(\t\x12/\n\ncandidates\x18\x02 \x03(\x0b\x32\x1b.antd.v1.CandidateNodeEntry\"=\n\x12\x43\x61ndidateNodeEntry\x12\x17\n\x0frewards_address\x18\x01 \x01(\t\x12\x0e\n\x06\x61mount\x18\x02 \x01(\t\"\xea\x01\n\x15\x46inalizeUploadRequest\x12\x11\n\tupload_id\x18\x01 \x01(\t\x12?\n\ttx_hashes\x18\x02 \x03(\x0b\x32,.antd.v1.FinalizeUploadRequest.TxHashesEntry\x12\x18\n\x10winner_pool_hash\x18\x03 \x01(\t\x12\x1a\n\x12winner_pool_hashes\x18\x05 \x03(\t\x12\x16\n\x0estore_data_map\x18\x04 \x01(\x08\x1a/\n\rTxHashesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"l\n\x16\x46inalizeUploadResponse\x12\x10\n\x08\x64\x61ta_map\x18\x01 \x01(\t\x12\x0f\n\x07\x61\x64\x64ress\x18\x02 \x01(\t\x12\x18\n\x10\x64\x61ta_map_address\x18\x03 \x01(\t\x12\x15\n\rchunks_stored\x18\x04 \x01(\x04\x32\x92\x02\n\rUploadService\x12V\n\x11PrepareFileUpload\x12!.antd.v1.PrepareFileUploadRequest\x1a\x1e.antd.v1.PrepareUploadResponse\x12V\n\x11PrepareDataUpload\x12!.antd.v1.PrepareDataUploadRequest\x1a\x1e.antd.v1.PrepareUploadResponse\x12Q\n\x0e\x46inalizeUpload\x12\x1e.antd.v1.FinalizeUploadRequest\x1a\x1f.antd.v1.FinalizeUploadResponseBDZ8github.com/WithAutonomi/ant-sdk/antd-go/proto/antd/v1;v1\xaa\x02\x07\x41ntd.V1b\x06proto3"
|
|
11
11
|
|
|
12
12
|
pool = ::Google::Protobuf::DescriptorPool.generated_pool
|
|
13
13
|
pool.add_serialized_file(descriptor_data)
|
|
@@ -17,6 +17,7 @@ module Antd
|
|
|
17
17
|
PrepareFileUploadRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("antd.v1.PrepareFileUploadRequest").msgclass
|
|
18
18
|
PrepareDataUploadRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("antd.v1.PrepareDataUploadRequest").msgclass
|
|
19
19
|
PrepareUploadResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("antd.v1.PrepareUploadResponse").msgclass
|
|
20
|
+
MerkleBatchEntry = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("antd.v1.MerkleBatchEntry").msgclass
|
|
20
21
|
PoolCommitmentEntry = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("antd.v1.PoolCommitmentEntry").msgclass
|
|
21
22
|
CandidateNodeEntry = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("antd.v1.CandidateNodeEntry").msgclass
|
|
22
23
|
FinalizeUploadRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("antd.v1.FinalizeUploadRequest").msgclass
|
|
@@ -40,8 +40,10 @@ module Antd
|
|
|
40
40
|
rpc :PrepareDataUpload, ::Antd::V1::PrepareDataUploadRequest, ::Antd::V1::PrepareUploadResponse
|
|
41
41
|
# Phase 2: finalize an upload after the external EVM payment has landed.
|
|
42
42
|
# For wave-batch uploads pass `tx_hashes`; for merkle uploads pass
|
|
43
|
-
# `
|
|
44
|
-
#
|
|
43
|
+
# `winner_pool_hashes` — one `MerklePaymentMade` winner hash per entry in
|
|
44
|
+
# the prepare response's `merkle_batches` (`winner_pool_hash` remains
|
|
45
|
+
# accepted when there is exactly one batch). The server-side stored upload
|
|
46
|
+
# state is consumed (one-shot) once inputs validate.
|
|
45
47
|
rpc :FinalizeUpload, ::Antd::V1::FinalizeUploadRequest, ::Antd::V1::FinalizeUploadResponse
|
|
46
48
|
end
|
|
47
49
|
|
data/lib/antd/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: antd
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- WithAutonomi
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-09-
|
|
11
|
+
date: 2026-09-25 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: grpc
|