diff --git a/UCALLBACK_IMPLEMENTATION.md b/UCALLBACK_IMPLEMENTATION.md new file mode 100644 index 00000000..2022d86b --- /dev/null +++ b/UCALLBACK_IMPLEMENTATION.md @@ -0,0 +1,569 @@ +# `x/ucallback` — core implementation guide + +**Companion to** `UCALLBACK_MODULE_PLAN.md` (architecture, rationale, open questions). +This file is the build order. Section numbers below match the **actual commits** on +`feat/read-state`, which diverged from the original plan — scaffolding landed before protos, state was +split out of the skeleton, and the protocgen fix was unplanned: + +| # | commit | state | +|---|---|---| +| C0 | `d2e033ce` fix(proto): stop protocgen deleting compat/orm-api | done (unplanned prerequisite) | +| C1 | `b9c966f3` feat(ucallback): scaffold module | done | +| C2 | `d0ad5720` feat(ucallback): add read-state types | done | +| C3 | keeper state + indexes | **staged, in review** | +| C4 | queries | next — unblocks the UV team | +| C5–C9 | ingestion → vote → hook → sweeper → upgrade | planned | + +**Design decisions already locked** (see plan §2 for evidence): + +| decision | why | +|---|---| +| new module `x/ucallback` | clean separation from uexecutor | +| EVM calls made **as the uexecutor module account** | `UniversalCallback.sol:25` hardcodes `0x14191Ea5…` immutable; a `ucallback` module account is rejected by `onlyUEModule` | +| aggregate named `UniversalRead` | read-side sibling of `UniversalTx` | +| `error_msg` absent from the ballot proto entirely | convention-only exclusion will be forgotten once generated | +| ballot key computed over the *identical-mode subset* | v2 `MEDIAN` must be excluded or it's a consensus-breaking change later | +| ingest filters on `log.Address` **and** topic0 | we listen to one trusted contract; the filter is what makes that true | + +--- + +## RESOLVED — expiry semantics + +**Team decision: `expiryPushChainHeight` is the ballot expiry.** The two clocks are fused, not +independent — a read ballot expires exactly when its request does. + +| | clock | set by | enforced at | +|---|---|---|---| +| **A** | `ReadSpec.expiryPushChainHeight` → `ReadRequest.expiry_block_height` | the app, per request | `UniversalCallback.sol:121` on request, `:207` in `expireExternalRead` | +| **B** | `Ballot.block_height_expiry` | **derived from A** | `x/uvalidator/keeper/ballot.go:344` | + +x/uvalidator stores `BlockHeightExpiry = createdHeight + expiryAfterBlocks` +(`x/uvalidator/types/ballot.go:109`), so an absolute deadline has to be handed over as a delta — +`types.BallotExpiryAfterBlocks(expiryHeight, currentHeight)`, floored at 1 so a ballot is never born +expired. We do **not** copy x/uexecutor's inert `DefaultExpiryAfterBlocks = 100_000_000`. + +**What this changed downstream:** + +- An `EXPIRED` ballot now means *the request itself is over*, so the terminal hook retires it — + `expireExternalRead` + status `EXPIRED` — instead of leaving it for the sweeper. A request is + unvotable past its deadline anyway, so waiting would only delay closing it on the contract. +- `REJECTED` still leaves the request in flight; that is not a deadline. +- The C8 sweeper is **still needed**, for requests nobody ever voted on: no vote means no ballot, + which means no terminal hook ever fires. Both paths mark the record terminal, which removes it from + the in-flight set, so whichever runs first the other will not find it. + +Still open from the original three questions: + +1. **Is late fulfilment intended?** `fulfillExternalCallback` has no expiry check — only the + `fulfilledRequests` guard. With the clocks fused this is now narrower in practice (an expired + ballot retires the request promptly), but a quorum reached in the same block as expiry is still a + race between the two paths. +2. **`expireExternalRead` refunds nothing.** Unchanged and unaddressed: the funder's fee stays with + the protocol whichever way a request ends. + +## Reference points in existing code + +Copy these, don't invent: + +``` +x/uexecutor/keeper/evm_hooks.go:21 NewEVMHooks / PostTxProcessing shape +x/uexecutor/keeper/create_outbound.go:27-42 log scan: address filter → topic filter → decode +x/uexecutor/keeper/voting.go:73-125 VoteOnOutboundBallot — the exact voting template +x/uexecutor/keeper/ballot_hooks.go:56 AfterBallotTerminal dispatch +x/uexecutor/keeper/chain_meta.go median-without-ballots (relevant only for v2) +x/uexecutor/types/types.proto:186 UniversalTx shape · :123 PCTx (reuse) +proto/uexecutor/v1/tx.proto:121 MsgVoteOutbound shape +proto/uvalidator/v1/ballot.proto:25 BallotObservationType enum +app/app.go:794 EVMKeeper.SetHooks — currently single-hook +``` + +**The ballot model, stated plainly** — this shapes everything downstream: +`Ballot.votes` is a parallel array of binary `VoteResult{SUCCESS|FAILURE}`. The **ballot ID encodes the +observation**. Distinct observations produce distinct ballots; the one that reaches quorum wins. +Validators do not vote *values*. This is why `VoteChainMeta` bypasses ballots entirely to compute gas +medians, and why v2 `MEDIAN` cannot ride the ballot path. + +--- + +# C2 — protos · DONE `d0ad5720` + +**Files** +``` +proto/ucallback/v1/types.proto +proto/ucallback/v1/genesis.proto +proto/ucallback/v1/params.proto +``` + +```protobuf +// types.proto +message UniversalRead { + option (amino.name) = "ucallback/universal_read"; + option (gogoproto.equal) = true; + + string id = 1; // requestId, 0x-hex uint256 + ReadRequest request = 2; + ReadResult result = 3; // set when the ballot finalises + repeated uexecutor.v1.PCTx pc_tx = 4; // fulfil / expire attempts — REUSE + UniversalReadStatus status = 5; + string ballot_key = 6; +} + +message ReadRequest { + string request_id = 1; + string destination_chain = 2; // CAIP-2, composed by us + bytes owner = 3; + bytes query = 4; + uint32 min_confirmations = 5; + uint64 destination_block_height = 6; + uint64 expiry_block_height = 7; + uint64 created_at_height = 8; // derived from the log's block — NOT in the event + + // core-only, never read by the UV + string callback_target = 9; + string original_funder = 10; + string fees_deposited = 11; + string max_fee = 12; + string requested_tx_hash = 13; + uint64 requested_log_index = 14; +} + +// The ballot payload. NO error_msg field — deliberately. +message ReadResult { + ReadStatus status = 1; + bytes result_data = 2; + uint64 observed_block_height = 3; + bytes observed_block_hash = 4; + // reserved for v2 MEDIAN — excluded from the ballot key when populated + repeated AggregateValue aggregates = 5; +} + +message AggregateValue { + uint32 extract_index = 1; + uint32 mode = 2; + bytes value = 3; +} + +enum ReadStatus { + READ_STATUS_UNSPECIFIED = 0; + READ_STATUS_SUCCESS = 1; + READ_STATUS_ERROR = 2; +} + +enum UniversalReadStatus { + UNIVERSAL_READ_STATUS_UNSPECIFIED = 0; + UNIVERSAL_READ_STATUS_PENDING = 1; + UNIVERSAL_READ_STATUS_VOTING = 2; + UNIVERSAL_READ_STATUS_FULFILLED = 3; + UNIVERSAL_READ_STATUS_EXPIRED = 4; + UNIVERSAL_READ_STATUS_FAILED = 5; // quorum reached, callback reverted +} +``` + +**`ReadRequest` must satisfy `universalClient/uread/types.go:9` field-for-field** — that struct exists +only to be deleted once these types generate. + +**Generate:** `make proto-gen` (Docker required — not the script directly). + +**Verify:** `go build ./...`; generated types exist; `uread.ReadRequest` maps 1:1. + +--- + +# C1 + C3 — module skeleton `b9c966f3`, keeper state (staged) + +**Files** +``` +x/ucallback/module.go AppModule, depinject +x/ucallback/keeper/keeper.go collections wiring +x/ucallback/keeper/genesis.go InitGenesis / ExportGenesis +x/ucallback/types/{keys,codec,errors,constants}.go +app/app.go module registration + maccPerms +``` + +```go +type Keeper struct { + UniversalReads collections.Map[string, types.UniversalRead] + PendingByExpiry collections.KeySet[collections.Pair[uint64, string]] // in-flight set + ReadsByTxHash collections.KeySet[collections.Pair[string, string]] // (txHash, requestId) + Params collections.Item[types.Params] + + evmKeeper types.EVMKeeper + uexecutorKeeper types.UexecutorKeeper // for module addr + DerivedEVMCall + uvalidatorKeeper types.UvalidatorKeeper // for eligible voters + VoteOnBallot +} +``` + +`ReadsByTxHash` exists because a single Push transaction can emit several `ReadRequested` logs — +a batching app, or a contract that fires more than one `_requestRead` in one call. Each becomes its +own `UniversalRead` keyed by `requestId` (they share no lifecycle: one can be FULFILLED while its +sibling EXPIRES), so this index is what reassembles the batch for `reads-by-tx`. Ordered composite +key, prefix-scanned by `txHash`. + +`PendingByExpiry` **must** be an ordered composite key so the sweeper can range-scan +`[0, currentHeight]` rather than iterating the whole set. + +> Adding `ucallback` to `maccPerms` puts its address into `BlockedAddresses()`, and since cosmos/evm +> v0.7 that list also gates `SetBalance` — so the module address can't receive native EVM value. +> That is almost certainly correct here; note it if not. + +**Verify:** chain starts, genesis round-trips, `q ucallback params` responds. + +--- + +# C4 — queries ← **ship this early, it unblocks the UV team** + +**Files** +``` +proto/ucallback/v1/query.proto +x/ucallback/keeper/grpc_query.go +x/ucallback/client/cli/query.go +``` + +```protobuf +rpc AllPendingReadRequests(QueryAllPendingReadRequestsRequest) + returns (QueryAllPendingReadRequestsResponse); // paginated +rpc GetUniversalRead(QueryGetUniversalReadRequest) + returns (QueryGetUniversalReadResponse); +rpc ReadsByTxHash(QueryReadsByTxHashRequest) + returns (QueryReadsByTxHashResponse); // all reads from one Push tx +``` + +`AllPendingReadRequests` returns `[]ReadRequest` where status is `PENDING`. Mirror +`AllPendingOutbounds` for pagination shape. + +**Why third and not last:** it deletes `ErrReadQueriesNotAvailable` in +`universalClient/pushcore/pushCore.go:382` and lets the UV team integrate against a real endpoint — +even while it returns an empty list. Their TODO names this exact query. + +`ReadsByTxHash` prefix-scans `ReadsByTxHash` and returns the full `UniversalRead` for each hit — +`q ucallback reads-by-tx `. This is how a batched request is inspected as a unit, and it is why +we can key records by `requestId` without losing the grouping. + +`GetUniversalRead` is the operator tool. Model the CLI on `q uexecutor v2 get-universal-tx`; that query +is what made a stranded production tx diagnosable in minutes this week. + +**Verify:** UV team's `GetAllPendingReadRequests` returns `[]` instead of an error. + +--- + +# C5 — ingestion + +**Files** +``` +x/ucallback/keeper/evm_hooks.go +x/ucallback/keeper/ingest.go +x/ucallback/types/event_decode.go +app/app.go ← rewire to MultiEvmHooks +``` + +```go +func (h EVMHooks) PostTxProcessing(ctx sdk.Context, sender common.Address, + msg core.Message, receipt *ethtypes.Receipt) error { + if err := h.k.IngestReadRequests(ctx, receipt); err != nil { + h.k.Logger().Error("ucallback ingest failed", "tx", receipt.TxHash, "err", err) + } + return nil // NEVER non-nil — see below +} +``` + +> 🔴 `MultiEvmHooks.PostTxProcessing` aborts the whole hook chain on the first error +> (`x/vm/keeper/hooks.go:40-42`), which **fails the EVM transaction**. A bug in our hook would break +> unrelated user txs. Log and continue; never return an error for anything short of a consensus fault. + +```go +// ingest.go — mirrors create_outbound.go:27-42 +for _, lg := range receipt.Logs { + if lg.Removed { continue } + if !strings.EqualFold(lg.Address, ucAddr) { continue } + if len(lg.Topics) == 0 { continue } + if !strings.EqualFold(lg.Topics[0], ReadRequestedSig) { continue } + + ev, err := types.DecodeReadRequestedFromLog(lg) + if err != nil { k.Logger().Error(...); continue } + + if has, _ := k.UniversalReads.Has(ctx, ev.RequestID); has { continue } // idempotent + + ur := types.UniversalRead{ + Id: ev.RequestID, + Request: &types.ReadRequest{ + RequestId: ev.RequestID, + DestinationChain: ev.ChainNamespace + ":" + ev.ChainId, + Owner: ev.Owner, + Query: ev.Query, + MinConfirmations: uint32(ev.MinConfirmations), + DestinationBlockHeight: ev.BlockNumber, + ExpiryBlockHeight: ev.ExpiryPushChainHeight, + CreatedAtHeight: uint64(ctx.BlockHeight()), + CallbackTarget: ev.CallbackTarget, + OriginalFunder: ev.OriginalFunder, + FeesDeposited: ev.FeesDeposited.String(), + MaxFee: ev.MaxFee.String(), + RequestedTxHash: receipt.TxHash.Hex(), + RequestedLogIndex: uint64(lg.Index), + }, + Status: types.UNIVERSAL_READ_STATUS_PENDING, + } + k.UniversalReads.Set(ctx, ev.RequestID, ur) + k.PendingByExpiry.Set(ctx, collections.Join(ev.ExpiryPushChainHeight, ev.RequestID)) +} +``` + +**app.go — `SetHooks` panics if called twice** (`x/vm/keeper/keeper.go:255`), and line 794 already +registers uexecutor's: + +```go +app.EVMKeeper.SetHooks(evmkeeper.NewMultiEvmHooks( + uexecutorkeeper.NewEVMHooks(app.UexecutorKeeper), + ucallbackkeeper.NewEVMHooks(app.UcallbackKeeper), +)) +``` + +**⚠️ Put `ReadRequestedSig` and the `UniversalCallback` address in chain config, not Go constants.** +uexecutor hardcodes both, and that has already failed in production: `constants.go:56` still declares +`RescueFundsOnSourceChain(...)` for an event the contract renamed to `FundsRescued`, so it silently +matches nothing. Register these like `gateway_methods` / `vault_methods`. + +**Tests** +- a log from a **non-UniversalCallback** address is ignored (regression test — this is the filter that makes "we only listen to one trusted contract" true) +- wrong topic0 ignored +- duplicate log → single record +- `created_at_height` equals the block height, not anything from the event + +--- + +# C6 — vote message and ballot + +**Files** +``` +proto/uvalidator/v1/ballot.proto + BALLOT_OBSERVATION_TYPE_READ_RESULT = 5 +proto/ucallback/v1/tx.proto MsgVoteReadResult +x/ucallback/keeper/msg_vote_read_result.go +x/ucallback/keeper/voting.go VoteOnReadBallot +x/ucallback/types/keys.go GetReadBallotKey +``` + +```protobuf +rpc VoteReadResult(MsgVoteReadResult) returns (MsgVoteReadResultResponse); + +message MsgVoteReadResult { + option (amino.name) = "ucallback/MsgVoteReadResult"; + option (cosmos.msg.v1.signer) = "signer"; + string signer = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; + string request_id = 2; + ReadResult result = 3; +} +``` + +```go +// keys.go — mode-aware from day one. +// v1: every field is IDENTICAL, so this equals H(all of result_data). +// v2: aggregates are EXCLUDED here and medianed separately at quorum. +func GetReadBallotKey(requestId string, r *ReadResult) (string, error) { + // hash: requestId ‖ status ‖ result_data ‖ observed_block_height ‖ observed_block_hash + // NOT hashed: aggregates, and error_msg does not exist in the proto +} +``` + +```go +// voting.go — copy x/uexecutor/keeper/voting.go:73-125 verbatim, swapping the observation type +func (k Keeper) VoteOnReadBallot(ctx, universalValidator sdk.ValAddress, + requestId string, res *types.ReadResult) (isFinalized, isNew bool, err error) { + ballotKey, err := types.GetReadBallotKey(requestId, res) + voters, _ := k.uvalidatorKeeper.GetEligibleVoters(ctx) + votesNeeded := (types.VotesThresholdNumerator*len(voters))/types.VotesThresholdDenominator + 1 + + _, isFinalized, isNew, err = k.uvalidatorKeeper.VoteOnBallot( + ctx, ballotKey, + uvalidatortypes.BallotObservationType_BALLOT_OBSERVATION_TYPE_READ_RESULT, + universalValidator.String(), + uvalidatortypes.VoteResult_VOTE_RESULT_SUCCESS, + voterAddrStrs, int64(votesNeeded), + types.BallotExpiryAfterBlocks(req.ExpiryBlockHeight, ctx.BlockHeight()), + ) + // ballotKey is stored on the UniversalRead itself; there is no reverse index. + // AfterBallotTerminal resolves it by scanning PendingByExpiry — see + // GetUniversalReadByBallot. + return +} +``` + +**Msg server guards:** request exists · status is `PENDING` or `VOTING` · signer is an eligible +universal validator · not already `FULFILLED`/`EXPIRED`. + +**Open decision (plan Q2):** whether to reject `READ_STATUS_ERROR` ballots that carry no revert +evidence. PR #296's EVM executor votes ERROR on *any* `CallContract` failure — including pruned nodes +and 429s — and because ERROR ballots are byte-identical by design, infra faults converge into a +confident quorum. Decide before this commit lands. + +**Tests** +- two validators, identical results → one ballot, converges +- two validators, different `result_data` → two ballots, neither converges +- non-validator signer rejected +- vote on a `FULFILLED` request rejected + +--- + +# C7 — ballot terminal hook and fulfilment + +**Files** +``` +x/ucallback/keeper/ballot_hooks.go +x/ucallback/keeper/fulfill.go +x/ucallback/types/abi.go UniversalCallback ABI +``` + +```go +func (h BallotHooks) AfterBallotTerminal(ctx, ballotKey string, + ballotType uvalidatortypes.BallotObservationType, ...) error { + switch ballotType { + case uvalidatortypes.BallotObservationType_BALLOT_OBSERVATION_TYPE_READ_RESULT: + return h.afterReadBallotTerminal(ctx, ballotKey) + } + return nil +} +``` + +```go +// fulfill.go +func (k Keeper) FulfillRead(ctx sdk.Context, ur types.UniversalRead) error { + abi, _ := types.ParseUniversalCallbackABI() + ueModuleAcc, _ := k.uexecutorKeeper.GetUeModuleAddress(ctx) + isModuleSender, nonce, _ := k.uexecutorKeeper.ModuleSenderNonce(ctx, ueModuleAcc) + + resp, err := k.evmKeeper.DerivedEVMCall( + ctx, abi, + ueModuleAcc, // MUST be uexecutor — contract hardcodes 0x14191Ea5… + universalCallbackAddr, + big.NewInt(0), nil, // gasLimit nil — estimate, per house convention + true, /*commit*/ false, /*gasless*/ + isModuleSender, nonce, + "fulfillExternalCallback", + requestIdBig, ur.Result.ResultData, + ur.Result.ObservedBlockHeight, ur.Result.ObservedBlockHash, + ) + + ur.PcTx = append(ur.PcTx, &uexecutortypes.PCTx{ + BlockHeight: uint64(ctx.BlockHeight()), + Status: err == nil && resp != nil && resp.VmError == "", + ErrorMsg: errMsgOf(err, resp), // ← the field that saves you at 2am + }) + if success { ur.Status = FULFILLED } else { ur.Status = FAILED } + k.PendingByExpiry.Remove(ctx, collections.Join(ur.Request.ExpiryBlockHeight, ur.Id)) + k.UniversalReads.Set(ctx, ur.Id, ur) +} +``` + +> **Decision: `gasLimit` is `nil`.** Ten of the eleven existing `DerivedEVMCall` sites pass `nil` +> and let `EstimateGasInternal` size it; only `CallUEAExecutePayload` passes a value, and only +> because the user's signed payload supplies one. We follow the convention. +> +> Consequence: we never need `callbackGasLimit`, so there is no `getPendingRead` call in the fulfil +> path and no dependency on contracts emitting it in `ReadRequested`. +> +> Residual risk, recorded not mitigated: the estimator's own doc says it *"may underpredict"*, and a +> `nil` site is how `CallPRC20Deposit` produced `intrinsic gas too low` on donut this week. If a read +> ever underpredicts, that request fails terminally (F4). The fix would be passing an explicit limit +> here — localised to this one call. + +> 🔴 **Never set `FULFILLED` optimistically.** If the submit itself fails (nonce drift, gas), the +> ballot is terminal but the callback never landed — you must be able to retry until expiry. + +**Note the uexecutor module-nonce drift bug**: module-sender calls skip `ModuleAccountNonce` +increment. Fix it before adding a fourth caller, or `FulfillRead` inherits it. + +**Tests** +- quorum → `fulfillExternalCallback` called with exactly the voted values +- callback reverts → `FAILED` + `error_msg` recorded, no retry +- submit fails → status unchanged, still retryable +- gas: `gasleft()` at the call ≥ `callbackGasLimit` + +--- + +# C8 — expiry sweeper + +**Files** +``` +x/ucallback/keeper/expire.go +x/ucallback/module.go EndBlock +app/app.go SetOrderEndBlockers +``` + +```go +func (k Keeper) SweepExpired(ctx sdk.Context) error { + h := uint64(ctx.BlockHeight()) + rng := collections.NewPrefixUntilPairRange[uint64, string](h) + n := 0 + for iter, _ := k.PendingByExpiry.Iterate(ctx, rng); iter.Valid() && n < maxExpiriesPerBlock; iter.Next() { + // DerivedEVMCall → expireExternalRead(requestId), same sender rules as C7 + // record PCTx, status = EXPIRED, de-index + n++ + } +} +``` + +Bound it per block — unbounded makes a fat EndBlocker, too low and a backlog never drains. + +> **Narrower than originally planned.** With ballot expiry fused to the request deadline (see +> RESOLVED at the top), the terminal hook already retires any request that attracted at least one +> vote. The sweeper's remaining job is requests that were *never voted on* — no vote means no ballot, +> so no hook ever fires for them. Cadence is therefore not urgent: nothing user-visible depends on +> prompt expiry, and `expireExternalRead` refunds nothing either way. + +> The contract's `expireExternalRead` **transfers nothing** (verified: zero value-transfer statements), +> so the funder's fee is trapped. That is a contracts bug, not ours — but our sweeper is what makes it +> visible, so record it clearly in the `PCTx` and surface it in `GetUniversalRead`. + +**Tests** +- request past expiry swept exactly once +- request at exactly `expiryHeight` — decide inclusive/exclusive and pin it +- fulfil/expire race: contract's `fulfilledRequests` guard means first-wins; core must swallow the + loser's revert without corrupting status + +--- + +# C9 — upgrade handler + +**Files** +``` +app/upgrades//upgrade.go +app/upgrades.go +``` + +New store key → `StoreUpgrades.Added: []string{"ucallback"}`. + +**Not a no-op `RunMigrations` — the handler must also deploy UniversalCallback at 0xC2.** +Verified against donut (chain 42101, height 20,791,174): `0x…C2`, `0xF2…C2` and `0xF1…C2` are all +empty — `code: 0x`, balance 0, nonce 0. Only the explicitly-named `SYSTEM_CONTRACTS` entries +(`0xAA 0xB0 0xB1 0xB2 0xBC 0xC0 0xC1`) are live; every `RESERVED_*` slot (`0xA0 0xA5 0xB3 0xC2 0xCF`) +is empty, because the deploy loop in `x/uregistry/keeper/genesis.go` runs at `InitGenesis` only and +donut's genesis predates the `init()` that added those reservations. + +So promoting `RESERVED_C2` → `UNIVERSAL_CALLBACK` is free on donut (nothing there either way), but the +real contract will not appear on its own — the handler has to deploy the admin + impl + proxy triple +explicitly, the way genesis would have. + +> Related, and worth raising with the team separately: the F-2026-17025 squatting defence is **not in +> effect on donut**. The A/B/C reserved slots are empty and claimable there. Pre-existing, but we are +> about to place a contract in that range. + +**Verify with a real upgrade simulation** from the current donut release to this branch — the +established flow: start the old binary, submit `MsgSoftwareUpgrade` at a height well past the end of +the voting period, let cosmovisor swap, confirm `q upgrade applied`, then run a tx. + +> Set the proposal height generously past the **end of the voting period**, not just the submit +> height — two simulation proposals failed with `upgrade cannot be scheduled in the past` learning +> this. + +--- + +## Ordering rationale + +C1→C3 are prerequisites. **C4 (queries) is deliberately early**: it is cheap, it unblocks the UV team, +and it can ship returning an empty list. C5 (ingestion) makes records real. C6–C7 are the consensus +core and should land together in review even if committed separately. C8 (sweeper) is safe to add last +because until it exists, expired requests simply accumulate — no corruption. C9 gates deployment. + +## Cross-team dependencies + +Nothing here is blocked on contracts. But six contract defects change behaviour at the edges, and all +are cheap while `feat-read-state` is unmerged — F6 (**no status channel in +`fulfillExternalCallback`**) is the only one with no core-side workaround. Full list in the plan §10. diff --git a/UCALLBACK_MODULE_PLAN.md b/UCALLBACK_MODULE_PLAN.md new file mode 100644 index 00000000..bccad453 --- /dev/null +++ b/UCALLBACK_MODULE_PLAN.md @@ -0,0 +1,441 @@ +# `x/ucallback` — Read-from-Chains, core-side module plan + +**Status:** Draft for review · **Written:** 2026-08-04 +**Scope:** core chain only. Contracts (`push-chain-core-contracts@feat-read-state`) and universal +validators (`push-chain-node#296`) are owned by other teams; both are already written, which means +**our interface is pinned from both ends**. + +Every claim below is cited to a file:line or a live query. Open questions are collected in §9. + +--- + +## 1. What we own + +``` +┌─ contracts (done, branch) ┌─ UV (done, draft PR #296) +│ UniversalCallback.sol │ externalchains/{evm,svm,web2}/read_executor.go +│ emits ReadRequested │ pushwatcher/ → polls us +│ exposes fulfillExternalCallback │ pushcore.GetAllPendingReadRequests() ← STUB +│ expireExternalRead │ +└────────────┬───────────────────────────────┴──────────┬───────────────── + │ │ + ┌────▼──────────────────────────────────────────▼────┐ + │ x/ucallback ← US │ + │ ingest ReadRequested → serve pending → tally │ + │ ballot → call fulfill/expire → record outcome │ + └─────────────────────────────────────────────────────┘ +``` + +The UV's stub states our deliverable verbatim (`universalClient/pushcore/pushCore.go:377`): + +> `TODO(core): blocked on x/uexecutor Query/PendingReadRequests … mirror GetAllPendingOutbounds` + +Note it says `x/uexecutor`. We are choosing `x/ucallback` instead — see §2.1 for why that is fine +and §9 Q1 for the one thing it forces. + +--- + +## 2. Hard constraints discovered + +### 2.1 🔴 The EVM caller must be the **uexecutor** module account + +`UniversalCallback.sol:25` hardcodes an immutable: + +```solidity +address public immutable UNIVERSAL_EXECUTOR_MODULE = 0x14191Ea54B4c176fCf86f51b0FAc7CB1E71Df7d7; +modifier onlyUEModule() { if (msg.sender != UNIVERSAL_EXECUTOR_MODULE) revert CallerIsNotUEModule(); } +``` + +Verified against live donut: + +``` +uexecutor module push1zsv3af2tfstklnux75dsltruk8n3ma7hnxp8ew + → hex 0x14191ea54b4c176fcf86f51b0fac7cb1e71df7d7 ← identical +``` + +A new module gets `authtypes.NewModuleAddress("ucallback")`, a **different** address. Every +`fulfillExternalCallback` would revert. + +**Decision taken:** `x/ucallback` owns state and lifecycle; the EVM call is executed *as uexecutor* +by calling into the uexecutor keeper. No contract change, no redeploy coupling. + +> Consequence: we inherit uexecutor's module-nonce path, including the known drift bug where +> module-sender calls skip `ModuleAccountNonce` increment. Fix that before adding a fourth caller. + +### 2.2 🔴 `SetHooks` panics if called twice + +`x/vm/keeper/keeper.go:254`: + +```go +func (k *Keeper) SetHooks(eh types.EvmHooks) *Keeper { + if k.hooks != nil { panic("cannot set evm hooks twice") } +``` + +and `app/app.go:794` already does `app.EVMKeeper.SetHooks(uexecutorkeeper.NewEVMHooks(...))`. + +**Solution:** `evmkeeper.NewMultiEvmHooks(uexecutorHooks, ucallbackHooks)` (`x/vm/keeper/hooks.go:27`). + +> ⚠️ `MultiEvmHooks.PostTxProcessing` aborts the whole chain of hooks on the first error +> (`hooks.go:40-42`). A bug in our hook therefore **fails unrelated EVM transactions**. Our hook +> must never return a non-nil error for anything short of a genuine consensus fault — log and +> continue instead. + +### 2.3 🟡 Known defects on the contract side we must design around + +| defect | effect on us | +|---|---| +| `expireExternalRead` transfers nothing (verified: 0 value-transfer statements) | our sweeper "expires" a request but the funder is never repaid; fees accrue in the contract | +| refund uses `call{value}` + `revert` on failure | an app without `receive()` makes `fulfillExternalCallback` revert **forever**; our submit will never succeed | +| `fulfilledRequests[requestId] = true` set *before* dispatch | whatever we submit is final; a quorum on ERROR is permanent, no retry | +| `_localContext` leaks in the app on the failure/expiry paths | not ours, but it's what users will report to us | + +These are raised with the contracts team (§10). Our design must not *depend* on them being fixed. + +--- + +## 3. Data model + +### 3.1 `UniversalRead` — the aggregate + +Named as the read-side sibling of `UniversalTx` (`proto/uexecutor/v1/types.proto:186`). Deliberately +**not** a clone: a read is triggered by a Push-chain event, performs no external write, has no +external tx hash, and produces exactly one Push-chain fulfilment. + +```protobuf +// proto/ucallback/v1/types.proto +message UniversalRead { + option (amino.name) = "ucallback/universal_read"; + + string id = 1; // requestId, 0x-hex uint256 + ReadRequest request = 2; + ReadResult result = 3; // set when the ballot finalises + repeated PCTx pc_tx = 4; // fulfil / expire attempts (reuse uexecutor's PCTx) + UniversalReadStatus status = 5; + string ballot_key = 6; +} +``` + +`pc_tx` is repeated (fulfil, then possibly expire); `request`/`result` are singular. There is no +top-level `revert_error` — failures live in `PCTx.error_msg`, which is the field that made a stuck +`UniversalTx` debuggable in production. + +### 3.2 `ReadRequest` — served verbatim to UVs + +```protobuf +message ReadRequest { + string request_id = 1; + string destination_chain = 2; // CAIP-2, composed by us + bytes owner = 3; + bytes query = 4; + uint32 min_confirmations = 5; // uint16 on the wire + uint64 destination_block_height = 6; + uint64 expiry_block_height = 7; + uint64 created_at_height = 8; // derived — NOT in the event + + // core-only, never consumed by the UV + string callback_target = 9; + string original_funder = 10; + string fees_deposited = 11; // uint256 as string + string max_fee = 12; + string requested_tx_hash = 13; // provenance / dedup / debugging + uint64 requested_log_index = 14; +} +``` + +Field-for-field this must satisfy `uread.ReadRequest` (`universalClient/uread/types.go:9`), the +temporary struct we are meant to delete. + +### 3.3 `ReadResult` — the ballot payload + +```protobuf +message ReadResult { + ReadStatus status = 1; + bytes result_data = 2; + uint64 observed_block_height = 3; + bytes observed_block_hash = 4; +} +``` + +**`error_msg` is deliberately absent from the proto**, not merely unused. In `uread` it is excluded +by a comment — *"local diagnostic only — never part of the ballot"*. Once it is a generated type +that convention will be forgotten; make it structurally impossible. If error text ever enters the +ballot key, no two validators ever agree. + +### 3.4 Enums + +```protobuf +enum ReadStatus { READ_STATUS_UNSPECIFIED = 0; READ_STATUS_SUCCESS = 1; READ_STATUS_ERROR = 2; } + +enum UniversalReadStatus { + UNIVERSAL_READ_STATUS_UNSPECIFIED = 0; + UNIVERSAL_READ_STATUS_PENDING = 1; // ingested, awaiting votes + UNIVERSAL_READ_STATUS_VOTING = 2; // ≥1 vote, no quorum + UNIVERSAL_READ_STATUS_FULFILLED = 3; // callback dispatched OK + UNIVERSAL_READ_STATUS_EXPIRED = 4; // expireExternalRead submitted + UNIVERSAL_READ_STATUS_FAILED = 5; // quorum reached, callback reverted +} +``` + +### 3.5 Contract → our fields + +| our field | from `ReadRequested` | +|---|---| +| `request_id` | `requestId` | +| `destination_chain` | `account.chainNamespace + ":" + account.chainId` | +| `owner` / `query` / `min_confirmations` | `account.owner` / `readSpec.query` / `readSpec.minConfirmations` | +| `destination_block_height` | `readSpec.blockNumber` | +| `expiry_block_height` | `readSpec.expiryPushChainHeight` | +| `callback_target` / `original_funder` / `fees_deposited` / `max_fee` | same-named event args | +| **`created_at_height`** | **not emitted** — take from the log's Push block height | + +--- + +## 4. Storage + +``` +UniversalReads : requestId → UniversalRead (collections.Map) +PendingByExpiry : (expiryHeight, requestId) → () (KeySet, in-flight set) +ReadsByTxHash : (pushTxHash, requestId) → () (KeySet, batch reassembly) +Params : module params +``` + +There is deliberately **no `ballotKey → requestId` index**. The ballot terminal hook resolves a ballot +by scanning `PendingByExpiry`, which holds only unsettled reads — the same trade uexecutor already +makes in `ballot_hooks.go:86` for the identical problem. That leaves `PendingByExpiry` with two +consumers, so it stays regardless of how the open expiry-cadence question is answered. + +`PendingByExpiry` must be an ordered composite key so the sweeper can range-scan +`[0, currentHeight]` in `EndBlocker` rather than iterating everything. + +--- + +## 5. Components + +``` +proto/ucallback/v1/{types,tx,query,genesis,params}.proto +x/ucallback/ + keeper/ + keeper.go collections wiring, uexecutor + uvalidator keeper refs + evm_hooks.go PostTxProcessing → ingest ReadRequested + ingest.go log filter + decode → UniversalRead{PENDING} + msg_vote_read_result.go MsgVoteReadResult → VoteOnReadBallot + ballot_hooks.go AfterBallotTerminal(READ_RESULT) → fulfil + fulfill.go call UniversalCallback.fulfillExternalCallback via uexecutor + expire.go EndBlocker sweeper → expireExternalRead + grpc_query.go AllPendingReadRequests, GetUniversalRead + types/ + constants.go keys.go codec.go errors.go events.go + module.go / depinject +``` + +### 5.1 Ingestion (`evm_hooks.go` + `ingest.go`) + +Mirrors `x/uexecutor/keeper/create_outbound.go:27-42`: + +```go +for _, lg := range receipt.Logs { + if lg.Removed { continue } + if !strings.EqualFold(lg.Address, universalCallbackAddr) { continue } // ← MANDATORY + if len(lg.Topics) == 0 || !strings.EqualFold(lg.Topics[0], ReadRequestedEventSig) { continue } + ... +} +``` + +**The address filter is a security control, not a nicety.** Matching on topic0 alone lets anyone +deploy a contract emitting an identical `ReadRequested` and conscript the entire validator set into +performing free external reads — a cheap DoS. The eventual `fulfillExternalCallback` would be +rejected (`InvalidRequestId`), so no funds move, but validator work and module txs are burned. + +### 5.2 Query (`grpc_query.go`) + +```protobuf +rpc AllPendingReadRequests(QueryAllPendingReadRequestsRequest) + returns (QueryAllPendingReadRequestsResponse); // paginated, mirrors AllPendingOutbounds +rpc GetUniversalRead(QueryGetUniversalReadRequest) + returns (QueryGetUniversalReadResponse); // mirrors v2 GetUniversalTx +``` + +`AllPendingReadRequests` is the one the UV is blocked on. `GetUniversalRead` is the operator tool — +the `get-universal-tx` equivalent that made a stuck production tx diagnosable in minutes. + +### 5.3 Voting + +```protobuf +rpc VoteReadResult(MsgVoteReadResult) returns (MsgVoteReadResultResponse); + +message MsgVoteReadResult { + option (cosmos.msg.v1.signer) = "signer"; + string signer = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; + string request_id = 2; + ReadResult result = 3; +} +``` + +Mirrors `MsgVoteOutbound` (`proto/uexecutor/v1/tx.proto:121`). Requires a new enum value in +`proto/uvalidator/v1/ballot.proto:25`: + +```protobuf +BALLOT_OBSERVATION_TYPE_READ_RESULT = 5; +``` + +`ballotKey = H(requestId ‖ status ‖ resultData ‖ observedBlockHeight ‖ observedBlockHash)` — +**excluding** error text. + +### 5.4 Ballot terminal hook + +Extend `BallotHooks.AfterBallotTerminal` (`x/uexecutor/keeper/ballot_hooks.go:56`) with a +`BALLOT_OBSERVATION_TYPE_READ_RESULT` case → `afterReadBallotTerminal` → §5.5. + +### 5.5 Fulfilment + +Call `UniversalCallback.fulfillExternalCallback(requestId, resultData, observedBlockHeight, +observedBlockHash)` through uexecutor's `DerivedEVMCall` so `msg.sender` is the uexecutor module +(§2.1). Record the outcome as a `PCTx` — **including `error_msg` on failure** — and set status +`FULFILLED` or `FAILED`. + +> `fulfillExternalCallback` does `call{gas: callbackGasLimit}` with `callbackGasLimit` up to +> `MAX_CALLBACK_GAS_LIMIT = 1_000_000` and performs **no 63/64 check**. Since we are the caller, we +> must ensure `gasleft() ≥ callbackGasLimit × 64/63 + buffer` before dispatch, or the callback +> silently under-runs and fails permanently. + +### 5.6 Expiry sweeper + +`EndBlocker`: range-scan `PendingByExpiry` over `[0, ctx.BlockHeight()]`, submit +`expireExternalRead(requestId)`, mark `EXPIRED`. Bound the per-block count (§9 Q5). + +--- + +## 6. Wiring (`app/app.go`) + +```go +app.EVMKeeper.SetHooks(evmkeeper.NewMultiEvmHooks( + uexecutorkeeper.NewEVMHooks(app.UexecutorKeeper), + ucallbackkeeper.NewEVMHooks(app.UcallbackKeeper), +)) +``` + +Replaces the single-hook call at `app/app.go:794`. Plus: module registration, `SetOrderEndBlockers` +entry for the sweeper, and a `ucallback` entry in `maccPerms`. + +> `BlockedAddresses()` derives from `GetMaccPerms()`, and since cosmos/evm v0.7 the blocked list also +> gates `SetBalance`. Adding `ucallback` to `maccPerms` therefore makes its address unable to receive +> native EVM value. That is almost certainly what we want — flag it if not. + +--- + +## 7. Delivery order + +1. protos + generated types (`make proto-gen`, Docker) +2. storage + keeper skeleton + genesis +3. `AllPendingReadRequests` → **unblocks the UV team immediately**, even returning empty +4. ingestion hook + `MultiEvmHooks` rewire +5. `MsgVoteReadResult` + ballot type + tally +6. terminal hook → fulfilment +7. expiry sweeper +8. `GetUniversalRead` + CLI +9. upgrade handler (new store key → `StoreUpgrades.Added`) + +Step 3 is deliberately early and cheap: it deletes `ErrReadQueriesNotAvailable` and lets the UV team +integrate against a real endpoint while the rest lands. + +--- + +## 8. Testing + +- ingestion: forged log from a non-`UniversalCallback` address is **ignored** (security regression test) +- ballot: two validators voting identical results converge; differing `error_msg` must not split them +- fulfilment: callback revert → `FAILED` + `error_msg` recorded, request not retried +- expiry: request past `expiry_block_height` is swept exactly once +- upgrade sim from the current donut release with the new store key + +--- + +## 9. Open questions / decisions needed + +**Q1 — module name vs the UV's expectation.** +The UV stub targets `x/uexecutor Query/PendingReadRequests`. If we ship `x/ucallback`, the UV team +must change the client path and proto import. Cheap, but it is a cross-team change that must be +agreed *before* they unblock. **Do we confirm `ucallback` with them now?** + +**Q2 — should we ever submit an ERROR ballot?** +PR #296's EVM executor votes ERROR on *any* `CallContract` failure +(`externalchains/evm/read_executor.go:61`), including non-archive nodes, 429s and timeouts — while +the SVM and web2 executors correctly treat transport failures as transient. Because ERROR ballots are +byte-identical by design, validators failing for unrelated infrastructure reasons converge into a +confident quorum indistinguishable from a genuine revert — and the contract makes it permanent. +**Do we harden core-side (refuse ERROR ballots lacking revert evidence), or require the UV fix first?** + +**Q3 — retry semantics.** +The contract marks `fulfilledRequests[requestId] = true` before dispatch, so a reverted callback is +terminal. Do we (a) accept that and record `FAILED`, or (b) ask contracts to mark fulfilled only on +success so a retry is possible? (b) is a contract change and must be requested while they are still +on a branch. + +**Q4 — do we gate on Push-chain confirmations before serving a request?** +The UV sets `ConfirmationType: store.ConfirmationInstant` (`pushwatcher/event_parser.go:114`) — it +acts immediately on whatever we serve. If we serve from a block that later reorgs, validators do work +for a request that never existed. **Serve immediately, or hold N blocks?** + +**Q5 — sweeper budget.** +Max expiries per block? Unbounded risks a fat EndBlocker; too low and a backlog never drains. + +**Q6 — who pays for callback gas?** +There is **no validator/reader reward path anywhere in `UniversalCallback.sol`** (grep: 0 matches). +The `callbackGasLimit × tx.gasprice` component is collected then refunded in full on both success and +failure — it pays nobody. The module bears real execution cost for up to 1M gas per read, gasless. +**Is that intentional for v1?** + +**Q7 — `ReadRequested` topic + `UniversalCallback` address: config or Go constants?** +uexecutor hardcodes both (`types/constants.go`, `uregistrytypes.SYSTEM_CONTRACTS`). That pattern has +already failed once in production: `RescueFundsOnSourceChainEventSig` still declares a signature the +contract renamed to `FundsRescued`, and it silently matches nothing. **Strong recommendation: put both +in chain config**, like `gateway_methods` / `vault_methods`. + +**Q9 — 🔴 web2 reads cannot be expressed by the contract.** +The UV has a complete web2 path (`externalchains/web2/read_executor.go`, 418 lines, SSRF-hardened), +`uread` documents the CAIP form `web2:https` and marks `DestinationBlockHeight` *"not applicable for +web2"*. But the contracts contain **zero** web2 references, and `requestExternalReadSelf` rejects it: + +```solidity +if (spec.blockNumber == 0 + || spec.blockNumber > _universalCore.chainHeightByChainNamespace(...)) revert InvalidBlockNumber(); +if (spec.account.owner.length == 0) revert InvalidAccountId(); +if (spec.minConfirmations < MIN_CONFIRMATIONS_FLOOR) revert InvalidMinConfirmations(); +``` + +A web2 request would need a fabricated `blockNumber`, a fictional `web2` namespace height in +`UniversalCore` exceeding it, a dummy `owner` (the URL lives in `query`), and a meaningless +`minConfirmations ≥ 1`. + +Ballots still converge — every web2 voter reports height `0` and an empty hash — so the tally needs no +special case. The costs are (a) we persist and serve a fake `destination_block_height`, and (b) any +future confirmation-gating on our side must exempt web2. + +**Is web2 in scope for v1? If yes, the contract needs a namespace-aware validation branch. If no, the +UV's web2 executor is dead code and we should not model for it.** + +**Q8 — one `ucallback` per read type, or reuse for future callbacks?** +The name implies a general callback module. If future non-read callbacks are planned, `UniversalRead` +should probably sit under a broader `UniversalCallbackRecord` umbrella now rather than later. + +--- + +## 10. Cross-team asks + +**Contracts** (`feat-read-state`, pre-merge — cheapest to fix now): +1. `expireExternalRead` refunds nothing — funder's fee is trapped +2. refund `call{value}` + `revert` lets an app with no `receive()` brick its own fulfilment forever +3. `UniversalReadClient` has no `receive()`; `CrossLendMock` adds one privately, so tests pass and the + requirement is invisible to integrators +4. consider marking fulfilled only on callback success (Q3) +5. `chainHeightByChainNamespace` ignores `chainId`, so all `eip155` chains share one height +6. fee derived from requester-controlled `tx.gasprice` +7. **web2 reads are unrequestable** — validation assumes a blockchain (`blockNumber != 0`, non-empty + `owner`, `minConfirmations ≥ 1`) while the UV has a complete web2 executor (Q9). Needs either a + namespace-aware validation branch or an explicit "web2 is not in v1" decision + +**UV team** (#296): +1. `eth_call` transport failures must not become ERROR ballots (Q2) — copy the web2 executor's own + three-way transient/deterministic split +2. confirm the `ucallback` module path (Q1) +3. `uread` deletion once our generated types land diff --git a/api/ucallback/module/v1/module.pulsar.go b/api/ucallback/module/v1/module.pulsar.go new file mode 100644 index 00000000..311612d9 --- /dev/null +++ b/api/ucallback/module/v1/module.pulsar.go @@ -0,0 +1,503 @@ +// Code generated by protoc-gen-go-pulsar. DO NOT EDIT. +package modulev1 + +import ( + _ "cosmossdk.io/api/cosmos/app/v1alpha1" + fmt "fmt" + runtime "github.com/cosmos/cosmos-proto/runtime" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoiface "google.golang.org/protobuf/runtime/protoiface" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" +) + +var ( + md_Module protoreflect.MessageDescriptor +) + +func init() { + file_ucallback_module_v1_module_proto_init() + md_Module = File_ucallback_module_v1_module_proto.Messages().ByName("Module") +} + +var _ protoreflect.Message = (*fastReflection_Module)(nil) + +type fastReflection_Module Module + +func (x *Module) ProtoReflect() protoreflect.Message { + return (*fastReflection_Module)(x) +} + +func (x *Module) slowProtoReflect() protoreflect.Message { + mi := &file_ucallback_module_v1_module_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +var _fastReflection_Module_messageType fastReflection_Module_messageType +var _ protoreflect.MessageType = fastReflection_Module_messageType{} + +type fastReflection_Module_messageType struct{} + +func (x fastReflection_Module_messageType) Zero() protoreflect.Message { + return (*fastReflection_Module)(nil) +} +func (x fastReflection_Module_messageType) New() protoreflect.Message { + return new(fastReflection_Module) +} +func (x fastReflection_Module_messageType) Descriptor() protoreflect.MessageDescriptor { + return md_Module +} + +// Descriptor returns message descriptor, which contains only the protobuf +// type information for the message. +func (x *fastReflection_Module) Descriptor() protoreflect.MessageDescriptor { + return md_Module +} + +// Type returns the message type, which encapsulates both Go and protobuf +// type information. If the Go type information is not needed, +// it is recommended that the message descriptor be used instead. +func (x *fastReflection_Module) Type() protoreflect.MessageType { + return _fastReflection_Module_messageType +} + +// New returns a newly allocated and mutable empty message. +func (x *fastReflection_Module) New() protoreflect.Message { + return new(fastReflection_Module) +} + +// Interface unwraps the message reflection interface and +// returns the underlying ProtoMessage interface. +func (x *fastReflection_Module) Interface() protoreflect.ProtoMessage { + return (*Module)(x) +} + +// Range iterates over every populated field in an undefined order, +// calling f for each field descriptor and value encountered. +// Range returns immediately if f returns false. +// While iterating, mutating operations may only be performed +// on the current field descriptor. +func (x *fastReflection_Module) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { +} + +// Has reports whether a field is populated. +// +// Some fields have the property of nullability where it is possible to +// distinguish between the default value of a field and whether the field +// was explicitly populated with the default value. Singular message fields, +// member fields of a oneof, and proto2 scalar fields are nullable. Such +// fields are populated only if explicitly set. +// +// In other cases (aside from the nullable cases above), +// a proto3 scalar field is populated if it contains a non-zero value, and +// a repeated field is populated if it is non-empty. +func (x *fastReflection_Module) Has(fd protoreflect.FieldDescriptor) bool { + switch fd.FullName() { + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.module.v1.Module")) + } + panic(fmt.Errorf("message ucallback.module.v1.Module does not contain field %s", fd.FullName())) + } +} + +// Clear clears the field such that a subsequent Has call reports false. +// +// Clearing an extension field clears both the extension type and value +// associated with the given field number. +// +// Clear is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_Module) Clear(fd protoreflect.FieldDescriptor) { + switch fd.FullName() { + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.module.v1.Module")) + } + panic(fmt.Errorf("message ucallback.module.v1.Module does not contain field %s", fd.FullName())) + } +} + +// Get retrieves the value for a field. +// +// For unpopulated scalars, it returns the default value, where +// the default value of a bytes scalar is guaranteed to be a copy. +// For unpopulated composite types, it returns an empty, read-only view +// of the value; to obtain a mutable reference, use Mutable. +func (x *fastReflection_Module) Get(descriptor protoreflect.FieldDescriptor) protoreflect.Value { + switch descriptor.FullName() { + default: + if descriptor.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.module.v1.Module")) + } + panic(fmt.Errorf("message ucallback.module.v1.Module does not contain field %s", descriptor.FullName())) + } +} + +// Set stores the value for a field. +// +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType. +// When setting a composite type, it is unspecified whether the stored value +// aliases the source's memory in any way. If the composite value is an +// empty, read-only value, then it panics. +// +// Set is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_Module) Set(fd protoreflect.FieldDescriptor, value protoreflect.Value) { + switch fd.FullName() { + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.module.v1.Module")) + } + panic(fmt.Errorf("message ucallback.module.v1.Module does not contain field %s", fd.FullName())) + } +} + +// Mutable returns a mutable reference to a composite type. +// +// If the field is unpopulated, it may allocate a composite value. +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType +// if not already stored. +// It panics if the field does not contain a composite type. +// +// Mutable is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_Module) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.module.v1.Module")) + } + panic(fmt.Errorf("message ucallback.module.v1.Module does not contain field %s", fd.FullName())) + } +} + +// NewField returns a new value that is assignable to the field +// for the given descriptor. For scalars, this returns the default value. +// For lists, maps, and messages, this returns a new, empty, mutable value. +func (x *fastReflection_Module) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.module.v1.Module")) + } + panic(fmt.Errorf("message ucallback.module.v1.Module does not contain field %s", fd.FullName())) + } +} + +// WhichOneof reports which field within the oneof is populated, +// returning nil if none are populated. +// It panics if the oneof descriptor does not belong to this message. +func (x *fastReflection_Module) WhichOneof(d protoreflect.OneofDescriptor) protoreflect.FieldDescriptor { + switch d.FullName() { + default: + panic(fmt.Errorf("%s is not a oneof field in ucallback.module.v1.Module", d.FullName())) + } + panic("unreachable") +} + +// GetUnknown retrieves the entire list of unknown fields. +// The caller may only mutate the contents of the RawFields +// if the mutated bytes are stored back into the message with SetUnknown. +func (x *fastReflection_Module) GetUnknown() protoreflect.RawFields { + return x.unknownFields +} + +// SetUnknown stores an entire list of unknown fields. +// The raw fields must be syntactically valid according to the wire format. +// An implementation may panic if this is not the case. +// Once stored, the caller must not mutate the content of the RawFields. +// An empty RawFields may be passed to clear the fields. +// +// SetUnknown is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_Module) SetUnknown(fields protoreflect.RawFields) { + x.unknownFields = fields +} + +// IsValid reports whether the message is valid. +// +// An invalid message is an empty, read-only value. +// +// An invalid message often corresponds to a nil pointer of the concrete +// message type, but the details are implementation dependent. +// Validity is not part of the protobuf data model, and may not +// be preserved in marshaling or other operations. +func (x *fastReflection_Module) IsValid() bool { + return x != nil +} + +// ProtoMethods returns optional fastReflectionFeature-path implementations of various operations. +// This method may return nil. +// +// The returned methods type is identical to +// "google.golang.org/protobuf/runtime/protoiface".Methods. +// Consult the protoiface package documentation for details. +func (x *fastReflection_Module) ProtoMethods() *protoiface.Methods { + size := func(input protoiface.SizeInput) protoiface.SizeOutput { + x := input.Message.Interface().(*Module) + if x == nil { + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: 0, + } + } + options := runtime.SizeInputToOptions(input) + _ = options + var n int + var l int + _ = l + if x.unknownFields != nil { + n += len(x.unknownFields) + } + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: n, + } + } + + marshal := func(input protoiface.MarshalInput) (protoiface.MarshalOutput, error) { + x := input.Message.Interface().(*Module) + if x == nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + options := runtime.MarshalInputToOptions(input) + _ = options + size := options.Size(x) + dAtA := make([]byte, size) + i := len(dAtA) + _ = i + var l int + _ = l + if x.unknownFields != nil { + i -= len(x.unknownFields) + copy(dAtA[i:], x.unknownFields) + } + if input.Buf != nil { + input.Buf = append(input.Buf, dAtA...) + } else { + input.Buf = dAtA + } + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + unmarshal := func(input protoiface.UnmarshalInput) (protoiface.UnmarshalOutput, error) { + x := input.Message.Interface().(*Module) + if x == nil { + return protoiface.UnmarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Flags: input.Flags, + }, nil + } + options := runtime.UnmarshalInputToOptions(input) + _ = options + dAtA := input.Buf + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: Module: wiretype end group for non-group") + } + if fieldNum <= 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: Module: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := runtime.Skip(dAtA[iNdEx:]) + if err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if !options.DiscardUnknown { + x.unknownFields = append(x.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + } + iNdEx += skippy + } + } + + if iNdEx > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, nil + } + return &protoiface.Methods{ + NoUnkeyedLiterals: struct{}{}, + Flags: protoiface.SupportMarshalDeterministic | protoiface.SupportUnmarshalDiscardUnknown, + Size: size, + Marshal: marshal, + Unmarshal: unmarshal, + Merge: nil, + CheckInitialized: nil, + } +} + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.27.0 +// protoc (unknown) +// source: ucallback/module/v1/module.proto + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// Module is the app config object of the module. +// Learn more: https://docs.cosmos.network/main/building-modules/depinject +type Module struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *Module) Reset() { + *x = Module{} + if protoimpl.UnsafeEnabled { + mi := &file_ucallback_module_v1_module_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Module) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Module) ProtoMessage() {} + +// Deprecated: Use Module.ProtoReflect.Descriptor instead. +func (*Module) Descriptor() ([]byte, []int) { + return file_ucallback_module_v1_module_proto_rawDescGZIP(), []int{0} +} + +var File_ucallback_module_v1_module_proto protoreflect.FileDescriptor + +var file_ucallback_module_v1_module_proto_rawDesc = []byte{ + 0x0a, 0x20, 0x75, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x2f, 0x6d, 0x6f, 0x64, 0x75, + 0x6c, 0x65, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x12, 0x13, 0x75, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x2e, 0x6d, 0x6f, + 0x64, 0x75, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x1a, 0x20, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, + 0x61, 0x70, 0x70, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2f, 0x6d, 0x6f, 0x64, + 0x75, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x36, 0x0a, 0x06, 0x4d, 0x6f, 0x64, + 0x75, 0x6c, 0x65, 0x3a, 0x2c, 0xba, 0xc0, 0x96, 0xda, 0x01, 0x26, 0x0a, 0x24, 0x67, 0x69, 0x74, + 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x75, 0x73, 0x68, 0x63, 0x68, 0x61, 0x69, + 0x6e, 0x2f, 0x70, 0x75, 0x73, 0x68, 0x2d, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x2d, 0x6e, 0x6f, 0x64, + 0x65, 0x42, 0xdb, 0x01, 0x0a, 0x17, 0x63, 0x6f, 0x6d, 0x2e, 0x75, 0x63, 0x61, 0x6c, 0x6c, 0x62, + 0x61, 0x63, 0x6b, 0x2e, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x42, 0x0b, 0x4d, + 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x45, 0x67, 0x69, + 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x75, 0x73, 0x68, 0x63, 0x68, 0x61, + 0x69, 0x6e, 0x2f, 0x70, 0x75, 0x73, 0x68, 0x2d, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x2d, 0x6e, 0x6f, + 0x64, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x75, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, + 0x2f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x2f, 0x76, 0x31, 0x3b, 0x6d, 0x6f, 0x64, 0x75, 0x6c, + 0x65, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x55, 0x4d, 0x58, 0xaa, 0x02, 0x13, 0x55, 0x63, 0x61, 0x6c, + 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x2e, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x2e, 0x56, 0x31, 0xca, + 0x02, 0x13, 0x55, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x5c, 0x4d, 0x6f, 0x64, 0x75, + 0x6c, 0x65, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x1f, 0x55, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, + 0x6b, 0x5c, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, + 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x15, 0x55, 0x63, 0x61, 0x6c, 0x6c, 0x62, + 0x61, 0x63, 0x6b, 0x3a, 0x3a, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x3a, 0x3a, 0x56, 0x31, 0x62, + 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_ucallback_module_v1_module_proto_rawDescOnce sync.Once + file_ucallback_module_v1_module_proto_rawDescData = file_ucallback_module_v1_module_proto_rawDesc +) + +func file_ucallback_module_v1_module_proto_rawDescGZIP() []byte { + file_ucallback_module_v1_module_proto_rawDescOnce.Do(func() { + file_ucallback_module_v1_module_proto_rawDescData = protoimpl.X.CompressGZIP(file_ucallback_module_v1_module_proto_rawDescData) + }) + return file_ucallback_module_v1_module_proto_rawDescData +} + +var file_ucallback_module_v1_module_proto_msgTypes = make([]protoimpl.MessageInfo, 1) +var file_ucallback_module_v1_module_proto_goTypes = []interface{}{ + (*Module)(nil), // 0: ucallback.module.v1.Module +} +var file_ucallback_module_v1_module_proto_depIdxs = []int32{ + 0, // [0:0] is the sub-list for method output_type + 0, // [0:0] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_ucallback_module_v1_module_proto_init() } +func file_ucallback_module_v1_module_proto_init() { + if File_ucallback_module_v1_module_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_ucallback_module_v1_module_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Module); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_ucallback_module_v1_module_proto_rawDesc, + NumEnums: 0, + NumMessages: 1, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_ucallback_module_v1_module_proto_goTypes, + DependencyIndexes: file_ucallback_module_v1_module_proto_depIdxs, + MessageInfos: file_ucallback_module_v1_module_proto_msgTypes, + }.Build() + File_ucallback_module_v1_module_proto = out.File + file_ucallback_module_v1_module_proto_rawDesc = nil + file_ucallback_module_v1_module_proto_goTypes = nil + file_ucallback_module_v1_module_proto_depIdxs = nil +} diff --git a/api/ucallback/v1/genesis.pulsar.go b/api/ucallback/v1/genesis.pulsar.go new file mode 100644 index 00000000..7e0faec1 --- /dev/null +++ b/api/ucallback/v1/genesis.pulsar.go @@ -0,0 +1,1843 @@ +// Code generated by protoc-gen-go-pulsar. DO NOT EDIT. +package ucallbackv1 + +import ( + _ "cosmossdk.io/api/amino" + fmt "fmt" + runtime "github.com/cosmos/cosmos-proto/runtime" + _ "github.com/cosmos/gogoproto/gogoproto" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoiface "google.golang.org/protobuf/runtime/protoiface" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" +) + +var _ protoreflect.List = (*_GenesisState_2_list)(nil) + +type _GenesisState_2_list struct { + list *[]*UniversalReadEntry +} + +func (x *_GenesisState_2_list) Len() int { + if x.list == nil { + return 0 + } + return len(*x.list) +} + +func (x *_GenesisState_2_list) Get(i int) protoreflect.Value { + return protoreflect.ValueOfMessage((*x.list)[i].ProtoReflect()) +} + +func (x *_GenesisState_2_list) Set(i int, value protoreflect.Value) { + valueUnwrapped := value.Message() + concreteValue := valueUnwrapped.Interface().(*UniversalReadEntry) + (*x.list)[i] = concreteValue +} + +func (x *_GenesisState_2_list) Append(value protoreflect.Value) { + valueUnwrapped := value.Message() + concreteValue := valueUnwrapped.Interface().(*UniversalReadEntry) + *x.list = append(*x.list, concreteValue) +} + +func (x *_GenesisState_2_list) AppendMutable() protoreflect.Value { + v := new(UniversalReadEntry) + *x.list = append(*x.list, v) + return protoreflect.ValueOfMessage(v.ProtoReflect()) +} + +func (x *_GenesisState_2_list) Truncate(n int) { + for i := n; i < len(*x.list); i++ { + (*x.list)[i] = nil + } + *x.list = (*x.list)[:n] +} + +func (x *_GenesisState_2_list) NewElement() protoreflect.Value { + v := new(UniversalReadEntry) + return protoreflect.ValueOfMessage(v.ProtoReflect()) +} + +func (x *_GenesisState_2_list) IsValid() bool { + return x.list != nil +} + +var ( + md_GenesisState protoreflect.MessageDescriptor + fd_GenesisState_params protoreflect.FieldDescriptor + fd_GenesisState_universal_reads protoreflect.FieldDescriptor + fd_GenesisState_module_account_nonce protoreflect.FieldDescriptor +) + +func init() { + file_ucallback_v1_genesis_proto_init() + md_GenesisState = File_ucallback_v1_genesis_proto.Messages().ByName("GenesisState") + fd_GenesisState_params = md_GenesisState.Fields().ByName("params") + fd_GenesisState_universal_reads = md_GenesisState.Fields().ByName("universal_reads") + fd_GenesisState_module_account_nonce = md_GenesisState.Fields().ByName("module_account_nonce") +} + +var _ protoreflect.Message = (*fastReflection_GenesisState)(nil) + +type fastReflection_GenesisState GenesisState + +func (x *GenesisState) ProtoReflect() protoreflect.Message { + return (*fastReflection_GenesisState)(x) +} + +func (x *GenesisState) slowProtoReflect() protoreflect.Message { + mi := &file_ucallback_v1_genesis_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +var _fastReflection_GenesisState_messageType fastReflection_GenesisState_messageType +var _ protoreflect.MessageType = fastReflection_GenesisState_messageType{} + +type fastReflection_GenesisState_messageType struct{} + +func (x fastReflection_GenesisState_messageType) Zero() protoreflect.Message { + return (*fastReflection_GenesisState)(nil) +} +func (x fastReflection_GenesisState_messageType) New() protoreflect.Message { + return new(fastReflection_GenesisState) +} +func (x fastReflection_GenesisState_messageType) Descriptor() protoreflect.MessageDescriptor { + return md_GenesisState +} + +// Descriptor returns message descriptor, which contains only the protobuf +// type information for the message. +func (x *fastReflection_GenesisState) Descriptor() protoreflect.MessageDescriptor { + return md_GenesisState +} + +// Type returns the message type, which encapsulates both Go and protobuf +// type information. If the Go type information is not needed, +// it is recommended that the message descriptor be used instead. +func (x *fastReflection_GenesisState) Type() protoreflect.MessageType { + return _fastReflection_GenesisState_messageType +} + +// New returns a newly allocated and mutable empty message. +func (x *fastReflection_GenesisState) New() protoreflect.Message { + return new(fastReflection_GenesisState) +} + +// Interface unwraps the message reflection interface and +// returns the underlying ProtoMessage interface. +func (x *fastReflection_GenesisState) Interface() protoreflect.ProtoMessage { + return (*GenesisState)(x) +} + +// Range iterates over every populated field in an undefined order, +// calling f for each field descriptor and value encountered. +// Range returns immediately if f returns false. +// While iterating, mutating operations may only be performed +// on the current field descriptor. +func (x *fastReflection_GenesisState) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { + if x.Params != nil { + value := protoreflect.ValueOfMessage(x.Params.ProtoReflect()) + if !f(fd_GenesisState_params, value) { + return + } + } + if len(x.UniversalReads) != 0 { + value := protoreflect.ValueOfList(&_GenesisState_2_list{list: &x.UniversalReads}) + if !f(fd_GenesisState_universal_reads, value) { + return + } + } + if x.ModuleAccountNonce != uint64(0) { + value := protoreflect.ValueOfUint64(x.ModuleAccountNonce) + if !f(fd_GenesisState_module_account_nonce, value) { + return + } + } +} + +// Has reports whether a field is populated. +// +// Some fields have the property of nullability where it is possible to +// distinguish between the default value of a field and whether the field +// was explicitly populated with the default value. Singular message fields, +// member fields of a oneof, and proto2 scalar fields are nullable. Such +// fields are populated only if explicitly set. +// +// In other cases (aside from the nullable cases above), +// a proto3 scalar field is populated if it contains a non-zero value, and +// a repeated field is populated if it is non-empty. +func (x *fastReflection_GenesisState) Has(fd protoreflect.FieldDescriptor) bool { + switch fd.FullName() { + case "ucallback.v1.GenesisState.params": + return x.Params != nil + case "ucallback.v1.GenesisState.universal_reads": + return len(x.UniversalReads) != 0 + case "ucallback.v1.GenesisState.module_account_nonce": + return x.ModuleAccountNonce != uint64(0) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.GenesisState")) + } + panic(fmt.Errorf("message ucallback.v1.GenesisState does not contain field %s", fd.FullName())) + } +} + +// Clear clears the field such that a subsequent Has call reports false. +// +// Clearing an extension field clears both the extension type and value +// associated with the given field number. +// +// Clear is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_GenesisState) Clear(fd protoreflect.FieldDescriptor) { + switch fd.FullName() { + case "ucallback.v1.GenesisState.params": + x.Params = nil + case "ucallback.v1.GenesisState.universal_reads": + x.UniversalReads = nil + case "ucallback.v1.GenesisState.module_account_nonce": + x.ModuleAccountNonce = uint64(0) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.GenesisState")) + } + panic(fmt.Errorf("message ucallback.v1.GenesisState does not contain field %s", fd.FullName())) + } +} + +// Get retrieves the value for a field. +// +// For unpopulated scalars, it returns the default value, where +// the default value of a bytes scalar is guaranteed to be a copy. +// For unpopulated composite types, it returns an empty, read-only view +// of the value; to obtain a mutable reference, use Mutable. +func (x *fastReflection_GenesisState) Get(descriptor protoreflect.FieldDescriptor) protoreflect.Value { + switch descriptor.FullName() { + case "ucallback.v1.GenesisState.params": + value := x.Params + return protoreflect.ValueOfMessage(value.ProtoReflect()) + case "ucallback.v1.GenesisState.universal_reads": + if len(x.UniversalReads) == 0 { + return protoreflect.ValueOfList(&_GenesisState_2_list{}) + } + listValue := &_GenesisState_2_list{list: &x.UniversalReads} + return protoreflect.ValueOfList(listValue) + case "ucallback.v1.GenesisState.module_account_nonce": + value := x.ModuleAccountNonce + return protoreflect.ValueOfUint64(value) + default: + if descriptor.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.GenesisState")) + } + panic(fmt.Errorf("message ucallback.v1.GenesisState does not contain field %s", descriptor.FullName())) + } +} + +// Set stores the value for a field. +// +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType. +// When setting a composite type, it is unspecified whether the stored value +// aliases the source's memory in any way. If the composite value is an +// empty, read-only value, then it panics. +// +// Set is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_GenesisState) Set(fd protoreflect.FieldDescriptor, value protoreflect.Value) { + switch fd.FullName() { + case "ucallback.v1.GenesisState.params": + x.Params = value.Message().Interface().(*Params) + case "ucallback.v1.GenesisState.universal_reads": + lv := value.List() + clv := lv.(*_GenesisState_2_list) + x.UniversalReads = *clv.list + case "ucallback.v1.GenesisState.module_account_nonce": + x.ModuleAccountNonce = value.Uint() + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.GenesisState")) + } + panic(fmt.Errorf("message ucallback.v1.GenesisState does not contain field %s", fd.FullName())) + } +} + +// Mutable returns a mutable reference to a composite type. +// +// If the field is unpopulated, it may allocate a composite value. +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType +// if not already stored. +// It panics if the field does not contain a composite type. +// +// Mutable is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_GenesisState) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "ucallback.v1.GenesisState.params": + if x.Params == nil { + x.Params = new(Params) + } + return protoreflect.ValueOfMessage(x.Params.ProtoReflect()) + case "ucallback.v1.GenesisState.universal_reads": + if x.UniversalReads == nil { + x.UniversalReads = []*UniversalReadEntry{} + } + value := &_GenesisState_2_list{list: &x.UniversalReads} + return protoreflect.ValueOfList(value) + case "ucallback.v1.GenesisState.module_account_nonce": + panic(fmt.Errorf("field module_account_nonce of message ucallback.v1.GenesisState is not mutable")) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.GenesisState")) + } + panic(fmt.Errorf("message ucallback.v1.GenesisState does not contain field %s", fd.FullName())) + } +} + +// NewField returns a new value that is assignable to the field +// for the given descriptor. For scalars, this returns the default value. +// For lists, maps, and messages, this returns a new, empty, mutable value. +func (x *fastReflection_GenesisState) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "ucallback.v1.GenesisState.params": + m := new(Params) + return protoreflect.ValueOfMessage(m.ProtoReflect()) + case "ucallback.v1.GenesisState.universal_reads": + list := []*UniversalReadEntry{} + return protoreflect.ValueOfList(&_GenesisState_2_list{list: &list}) + case "ucallback.v1.GenesisState.module_account_nonce": + return protoreflect.ValueOfUint64(uint64(0)) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.GenesisState")) + } + panic(fmt.Errorf("message ucallback.v1.GenesisState does not contain field %s", fd.FullName())) + } +} + +// WhichOneof reports which field within the oneof is populated, +// returning nil if none are populated. +// It panics if the oneof descriptor does not belong to this message. +func (x *fastReflection_GenesisState) WhichOneof(d protoreflect.OneofDescriptor) protoreflect.FieldDescriptor { + switch d.FullName() { + default: + panic(fmt.Errorf("%s is not a oneof field in ucallback.v1.GenesisState", d.FullName())) + } + panic("unreachable") +} + +// GetUnknown retrieves the entire list of unknown fields. +// The caller may only mutate the contents of the RawFields +// if the mutated bytes are stored back into the message with SetUnknown. +func (x *fastReflection_GenesisState) GetUnknown() protoreflect.RawFields { + return x.unknownFields +} + +// SetUnknown stores an entire list of unknown fields. +// The raw fields must be syntactically valid according to the wire format. +// An implementation may panic if this is not the case. +// Once stored, the caller must not mutate the content of the RawFields. +// An empty RawFields may be passed to clear the fields. +// +// SetUnknown is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_GenesisState) SetUnknown(fields protoreflect.RawFields) { + x.unknownFields = fields +} + +// IsValid reports whether the message is valid. +// +// An invalid message is an empty, read-only value. +// +// An invalid message often corresponds to a nil pointer of the concrete +// message type, but the details are implementation dependent. +// Validity is not part of the protobuf data model, and may not +// be preserved in marshaling or other operations. +func (x *fastReflection_GenesisState) IsValid() bool { + return x != nil +} + +// ProtoMethods returns optional fastReflectionFeature-path implementations of various operations. +// This method may return nil. +// +// The returned methods type is identical to +// "google.golang.org/protobuf/runtime/protoiface".Methods. +// Consult the protoiface package documentation for details. +func (x *fastReflection_GenesisState) ProtoMethods() *protoiface.Methods { + size := func(input protoiface.SizeInput) protoiface.SizeOutput { + x := input.Message.Interface().(*GenesisState) + if x == nil { + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: 0, + } + } + options := runtime.SizeInputToOptions(input) + _ = options + var n int + var l int + _ = l + if x.Params != nil { + l = options.Size(x.Params) + n += 1 + l + runtime.Sov(uint64(l)) + } + if len(x.UniversalReads) > 0 { + for _, e := range x.UniversalReads { + l = options.Size(e) + n += 1 + l + runtime.Sov(uint64(l)) + } + } + if x.ModuleAccountNonce != 0 { + n += 1 + runtime.Sov(uint64(x.ModuleAccountNonce)) + } + if x.unknownFields != nil { + n += len(x.unknownFields) + } + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: n, + } + } + + marshal := func(input protoiface.MarshalInput) (protoiface.MarshalOutput, error) { + x := input.Message.Interface().(*GenesisState) + if x == nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + options := runtime.MarshalInputToOptions(input) + _ = options + size := options.Size(x) + dAtA := make([]byte, size) + i := len(dAtA) + _ = i + var l int + _ = l + if x.unknownFields != nil { + i -= len(x.unknownFields) + copy(dAtA[i:], x.unknownFields) + } + if x.ModuleAccountNonce != 0 { + i = runtime.EncodeVarint(dAtA, i, uint64(x.ModuleAccountNonce)) + i-- + dAtA[i] = 0x18 + } + if len(x.UniversalReads) > 0 { + for iNdEx := len(x.UniversalReads) - 1; iNdEx >= 0; iNdEx-- { + encoded, err := options.Marshal(x.UniversalReads[iNdEx]) + if err != nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, err + } + i -= len(encoded) + copy(dAtA[i:], encoded) + i = runtime.EncodeVarint(dAtA, i, uint64(len(encoded))) + i-- + dAtA[i] = 0x12 + } + } + if x.Params != nil { + encoded, err := options.Marshal(x.Params) + if err != nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, err + } + i -= len(encoded) + copy(dAtA[i:], encoded) + i = runtime.EncodeVarint(dAtA, i, uint64(len(encoded))) + i-- + dAtA[i] = 0xa + } + if input.Buf != nil { + input.Buf = append(input.Buf, dAtA...) + } else { + input.Buf = dAtA + } + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + unmarshal := func(input protoiface.UnmarshalInput) (protoiface.UnmarshalOutput, error) { + x := input.Message.Interface().(*GenesisState) + if x == nil { + return protoiface.UnmarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Flags: input.Flags, + }, nil + } + options := runtime.UnmarshalInputToOptions(input) + _ = options + dAtA := input.Buf + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: GenesisState: wiretype end group for non-group") + } + if fieldNum <= 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: GenesisState: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Params", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if x.Params == nil { + x.Params = &Params{} + } + if err := options.Unmarshal(dAtA[iNdEx:postIndex], x.Params); err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field UniversalReads", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.UniversalReads = append(x.UniversalReads, &UniversalReadEntry{}) + if err := options.Unmarshal(dAtA[iNdEx:postIndex], x.UniversalReads[len(x.UniversalReads)-1]); err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + iNdEx = postIndex + case 3: + if wireType != 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field ModuleAccountNonce", wireType) + } + x.ModuleAccountNonce = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + x.ModuleAccountNonce |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := runtime.Skip(dAtA[iNdEx:]) + if err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if !options.DiscardUnknown { + x.unknownFields = append(x.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + } + iNdEx += skippy + } + } + + if iNdEx > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, nil + } + return &protoiface.Methods{ + NoUnkeyedLiterals: struct{}{}, + Flags: protoiface.SupportMarshalDeterministic | protoiface.SupportUnmarshalDiscardUnknown, + Size: size, + Marshal: marshal, + Unmarshal: unmarshal, + Merge: nil, + CheckInitialized: nil, + } +} + +var ( + md_UniversalReadEntry protoreflect.MessageDescriptor + fd_UniversalReadEntry_key protoreflect.FieldDescriptor + fd_UniversalReadEntry_value protoreflect.FieldDescriptor +) + +func init() { + file_ucallback_v1_genesis_proto_init() + md_UniversalReadEntry = File_ucallback_v1_genesis_proto.Messages().ByName("UniversalReadEntry") + fd_UniversalReadEntry_key = md_UniversalReadEntry.Fields().ByName("key") + fd_UniversalReadEntry_value = md_UniversalReadEntry.Fields().ByName("value") +} + +var _ protoreflect.Message = (*fastReflection_UniversalReadEntry)(nil) + +type fastReflection_UniversalReadEntry UniversalReadEntry + +func (x *UniversalReadEntry) ProtoReflect() protoreflect.Message { + return (*fastReflection_UniversalReadEntry)(x) +} + +func (x *UniversalReadEntry) slowProtoReflect() protoreflect.Message { + mi := &file_ucallback_v1_genesis_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +var _fastReflection_UniversalReadEntry_messageType fastReflection_UniversalReadEntry_messageType +var _ protoreflect.MessageType = fastReflection_UniversalReadEntry_messageType{} + +type fastReflection_UniversalReadEntry_messageType struct{} + +func (x fastReflection_UniversalReadEntry_messageType) Zero() protoreflect.Message { + return (*fastReflection_UniversalReadEntry)(nil) +} +func (x fastReflection_UniversalReadEntry_messageType) New() protoreflect.Message { + return new(fastReflection_UniversalReadEntry) +} +func (x fastReflection_UniversalReadEntry_messageType) Descriptor() protoreflect.MessageDescriptor { + return md_UniversalReadEntry +} + +// Descriptor returns message descriptor, which contains only the protobuf +// type information for the message. +func (x *fastReflection_UniversalReadEntry) Descriptor() protoreflect.MessageDescriptor { + return md_UniversalReadEntry +} + +// Type returns the message type, which encapsulates both Go and protobuf +// type information. If the Go type information is not needed, +// it is recommended that the message descriptor be used instead. +func (x *fastReflection_UniversalReadEntry) Type() protoreflect.MessageType { + return _fastReflection_UniversalReadEntry_messageType +} + +// New returns a newly allocated and mutable empty message. +func (x *fastReflection_UniversalReadEntry) New() protoreflect.Message { + return new(fastReflection_UniversalReadEntry) +} + +// Interface unwraps the message reflection interface and +// returns the underlying ProtoMessage interface. +func (x *fastReflection_UniversalReadEntry) Interface() protoreflect.ProtoMessage { + return (*UniversalReadEntry)(x) +} + +// Range iterates over every populated field in an undefined order, +// calling f for each field descriptor and value encountered. +// Range returns immediately if f returns false. +// While iterating, mutating operations may only be performed +// on the current field descriptor. +func (x *fastReflection_UniversalReadEntry) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { + if x.Key != "" { + value := protoreflect.ValueOfString(x.Key) + if !f(fd_UniversalReadEntry_key, value) { + return + } + } + if x.Value != nil { + value := protoreflect.ValueOfMessage(x.Value.ProtoReflect()) + if !f(fd_UniversalReadEntry_value, value) { + return + } + } +} + +// Has reports whether a field is populated. +// +// Some fields have the property of nullability where it is possible to +// distinguish between the default value of a field and whether the field +// was explicitly populated with the default value. Singular message fields, +// member fields of a oneof, and proto2 scalar fields are nullable. Such +// fields are populated only if explicitly set. +// +// In other cases (aside from the nullable cases above), +// a proto3 scalar field is populated if it contains a non-zero value, and +// a repeated field is populated if it is non-empty. +func (x *fastReflection_UniversalReadEntry) Has(fd protoreflect.FieldDescriptor) bool { + switch fd.FullName() { + case "ucallback.v1.UniversalReadEntry.key": + return x.Key != "" + case "ucallback.v1.UniversalReadEntry.value": + return x.Value != nil + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.UniversalReadEntry")) + } + panic(fmt.Errorf("message ucallback.v1.UniversalReadEntry does not contain field %s", fd.FullName())) + } +} + +// Clear clears the field such that a subsequent Has call reports false. +// +// Clearing an extension field clears both the extension type and value +// associated with the given field number. +// +// Clear is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_UniversalReadEntry) Clear(fd protoreflect.FieldDescriptor) { + switch fd.FullName() { + case "ucallback.v1.UniversalReadEntry.key": + x.Key = "" + case "ucallback.v1.UniversalReadEntry.value": + x.Value = nil + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.UniversalReadEntry")) + } + panic(fmt.Errorf("message ucallback.v1.UniversalReadEntry does not contain field %s", fd.FullName())) + } +} + +// Get retrieves the value for a field. +// +// For unpopulated scalars, it returns the default value, where +// the default value of a bytes scalar is guaranteed to be a copy. +// For unpopulated composite types, it returns an empty, read-only view +// of the value; to obtain a mutable reference, use Mutable. +func (x *fastReflection_UniversalReadEntry) Get(descriptor protoreflect.FieldDescriptor) protoreflect.Value { + switch descriptor.FullName() { + case "ucallback.v1.UniversalReadEntry.key": + value := x.Key + return protoreflect.ValueOfString(value) + case "ucallback.v1.UniversalReadEntry.value": + value := x.Value + return protoreflect.ValueOfMessage(value.ProtoReflect()) + default: + if descriptor.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.UniversalReadEntry")) + } + panic(fmt.Errorf("message ucallback.v1.UniversalReadEntry does not contain field %s", descriptor.FullName())) + } +} + +// Set stores the value for a field. +// +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType. +// When setting a composite type, it is unspecified whether the stored value +// aliases the source's memory in any way. If the composite value is an +// empty, read-only value, then it panics. +// +// Set is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_UniversalReadEntry) Set(fd protoreflect.FieldDescriptor, value protoreflect.Value) { + switch fd.FullName() { + case "ucallback.v1.UniversalReadEntry.key": + x.Key = value.Interface().(string) + case "ucallback.v1.UniversalReadEntry.value": + x.Value = value.Message().Interface().(*UniversalRead) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.UniversalReadEntry")) + } + panic(fmt.Errorf("message ucallback.v1.UniversalReadEntry does not contain field %s", fd.FullName())) + } +} + +// Mutable returns a mutable reference to a composite type. +// +// If the field is unpopulated, it may allocate a composite value. +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType +// if not already stored. +// It panics if the field does not contain a composite type. +// +// Mutable is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_UniversalReadEntry) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "ucallback.v1.UniversalReadEntry.value": + if x.Value == nil { + x.Value = new(UniversalRead) + } + return protoreflect.ValueOfMessage(x.Value.ProtoReflect()) + case "ucallback.v1.UniversalReadEntry.key": + panic(fmt.Errorf("field key of message ucallback.v1.UniversalReadEntry is not mutable")) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.UniversalReadEntry")) + } + panic(fmt.Errorf("message ucallback.v1.UniversalReadEntry does not contain field %s", fd.FullName())) + } +} + +// NewField returns a new value that is assignable to the field +// for the given descriptor. For scalars, this returns the default value. +// For lists, maps, and messages, this returns a new, empty, mutable value. +func (x *fastReflection_UniversalReadEntry) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "ucallback.v1.UniversalReadEntry.key": + return protoreflect.ValueOfString("") + case "ucallback.v1.UniversalReadEntry.value": + m := new(UniversalRead) + return protoreflect.ValueOfMessage(m.ProtoReflect()) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.UniversalReadEntry")) + } + panic(fmt.Errorf("message ucallback.v1.UniversalReadEntry does not contain field %s", fd.FullName())) + } +} + +// WhichOneof reports which field within the oneof is populated, +// returning nil if none are populated. +// It panics if the oneof descriptor does not belong to this message. +func (x *fastReflection_UniversalReadEntry) WhichOneof(d protoreflect.OneofDescriptor) protoreflect.FieldDescriptor { + switch d.FullName() { + default: + panic(fmt.Errorf("%s is not a oneof field in ucallback.v1.UniversalReadEntry", d.FullName())) + } + panic("unreachable") +} + +// GetUnknown retrieves the entire list of unknown fields. +// The caller may only mutate the contents of the RawFields +// if the mutated bytes are stored back into the message with SetUnknown. +func (x *fastReflection_UniversalReadEntry) GetUnknown() protoreflect.RawFields { + return x.unknownFields +} + +// SetUnknown stores an entire list of unknown fields. +// The raw fields must be syntactically valid according to the wire format. +// An implementation may panic if this is not the case. +// Once stored, the caller must not mutate the content of the RawFields. +// An empty RawFields may be passed to clear the fields. +// +// SetUnknown is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_UniversalReadEntry) SetUnknown(fields protoreflect.RawFields) { + x.unknownFields = fields +} + +// IsValid reports whether the message is valid. +// +// An invalid message is an empty, read-only value. +// +// An invalid message often corresponds to a nil pointer of the concrete +// message type, but the details are implementation dependent. +// Validity is not part of the protobuf data model, and may not +// be preserved in marshaling or other operations. +func (x *fastReflection_UniversalReadEntry) IsValid() bool { + return x != nil +} + +// ProtoMethods returns optional fastReflectionFeature-path implementations of various operations. +// This method may return nil. +// +// The returned methods type is identical to +// "google.golang.org/protobuf/runtime/protoiface".Methods. +// Consult the protoiface package documentation for details. +func (x *fastReflection_UniversalReadEntry) ProtoMethods() *protoiface.Methods { + size := func(input protoiface.SizeInput) protoiface.SizeOutput { + x := input.Message.Interface().(*UniversalReadEntry) + if x == nil { + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: 0, + } + } + options := runtime.SizeInputToOptions(input) + _ = options + var n int + var l int + _ = l + l = len(x.Key) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } + if x.Value != nil { + l = options.Size(x.Value) + n += 1 + l + runtime.Sov(uint64(l)) + } + if x.unknownFields != nil { + n += len(x.unknownFields) + } + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: n, + } + } + + marshal := func(input protoiface.MarshalInput) (protoiface.MarshalOutput, error) { + x := input.Message.Interface().(*UniversalReadEntry) + if x == nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + options := runtime.MarshalInputToOptions(input) + _ = options + size := options.Size(x) + dAtA := make([]byte, size) + i := len(dAtA) + _ = i + var l int + _ = l + if x.unknownFields != nil { + i -= len(x.unknownFields) + copy(dAtA[i:], x.unknownFields) + } + if x.Value != nil { + encoded, err := options.Marshal(x.Value) + if err != nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, err + } + i -= len(encoded) + copy(dAtA[i:], encoded) + i = runtime.EncodeVarint(dAtA, i, uint64(len(encoded))) + i-- + dAtA[i] = 0x12 + } + if len(x.Key) > 0 { + i -= len(x.Key) + copy(dAtA[i:], x.Key) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.Key))) + i-- + dAtA[i] = 0xa + } + if input.Buf != nil { + input.Buf = append(input.Buf, dAtA...) + } else { + input.Buf = dAtA + } + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + unmarshal := func(input protoiface.UnmarshalInput) (protoiface.UnmarshalOutput, error) { + x := input.Message.Interface().(*UniversalReadEntry) + if x == nil { + return protoiface.UnmarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Flags: input.Flags, + }, nil + } + options := runtime.UnmarshalInputToOptions(input) + _ = options + dAtA := input.Buf + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: UniversalReadEntry: wiretype end group for non-group") + } + if fieldNum <= 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: UniversalReadEntry: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Key", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.Key = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Value", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if x.Value == nil { + x.Value = &UniversalRead{} + } + if err := options.Unmarshal(dAtA[iNdEx:postIndex], x.Value); err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := runtime.Skip(dAtA[iNdEx:]) + if err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if !options.DiscardUnknown { + x.unknownFields = append(x.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + } + iNdEx += skippy + } + } + + if iNdEx > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, nil + } + return &protoiface.Methods{ + NoUnkeyedLiterals: struct{}{}, + Flags: protoiface.SupportMarshalDeterministic | protoiface.SupportUnmarshalDiscardUnknown, + Size: size, + Marshal: marshal, + Unmarshal: unmarshal, + Merge: nil, + CheckInitialized: nil, + } +} + +var ( + md_Params protoreflect.MessageDescriptor + fd_Params_some_value protoreflect.FieldDescriptor +) + +func init() { + file_ucallback_v1_genesis_proto_init() + md_Params = File_ucallback_v1_genesis_proto.Messages().ByName("Params") + fd_Params_some_value = md_Params.Fields().ByName("some_value") +} + +var _ protoreflect.Message = (*fastReflection_Params)(nil) + +type fastReflection_Params Params + +func (x *Params) ProtoReflect() protoreflect.Message { + return (*fastReflection_Params)(x) +} + +func (x *Params) slowProtoReflect() protoreflect.Message { + mi := &file_ucallback_v1_genesis_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +var _fastReflection_Params_messageType fastReflection_Params_messageType +var _ protoreflect.MessageType = fastReflection_Params_messageType{} + +type fastReflection_Params_messageType struct{} + +func (x fastReflection_Params_messageType) Zero() protoreflect.Message { + return (*fastReflection_Params)(nil) +} +func (x fastReflection_Params_messageType) New() protoreflect.Message { + return new(fastReflection_Params) +} +func (x fastReflection_Params_messageType) Descriptor() protoreflect.MessageDescriptor { + return md_Params +} + +// Descriptor returns message descriptor, which contains only the protobuf +// type information for the message. +func (x *fastReflection_Params) Descriptor() protoreflect.MessageDescriptor { + return md_Params +} + +// Type returns the message type, which encapsulates both Go and protobuf +// type information. If the Go type information is not needed, +// it is recommended that the message descriptor be used instead. +func (x *fastReflection_Params) Type() protoreflect.MessageType { + return _fastReflection_Params_messageType +} + +// New returns a newly allocated and mutable empty message. +func (x *fastReflection_Params) New() protoreflect.Message { + return new(fastReflection_Params) +} + +// Interface unwraps the message reflection interface and +// returns the underlying ProtoMessage interface. +func (x *fastReflection_Params) Interface() protoreflect.ProtoMessage { + return (*Params)(x) +} + +// Range iterates over every populated field in an undefined order, +// calling f for each field descriptor and value encountered. +// Range returns immediately if f returns false. +// While iterating, mutating operations may only be performed +// on the current field descriptor. +func (x *fastReflection_Params) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { + if x.SomeValue != false { + value := protoreflect.ValueOfBool(x.SomeValue) + if !f(fd_Params_some_value, value) { + return + } + } +} + +// Has reports whether a field is populated. +// +// Some fields have the property of nullability where it is possible to +// distinguish between the default value of a field and whether the field +// was explicitly populated with the default value. Singular message fields, +// member fields of a oneof, and proto2 scalar fields are nullable. Such +// fields are populated only if explicitly set. +// +// In other cases (aside from the nullable cases above), +// a proto3 scalar field is populated if it contains a non-zero value, and +// a repeated field is populated if it is non-empty. +func (x *fastReflection_Params) Has(fd protoreflect.FieldDescriptor) bool { + switch fd.FullName() { + case "ucallback.v1.Params.some_value": + return x.SomeValue != false + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.Params")) + } + panic(fmt.Errorf("message ucallback.v1.Params does not contain field %s", fd.FullName())) + } +} + +// Clear clears the field such that a subsequent Has call reports false. +// +// Clearing an extension field clears both the extension type and value +// associated with the given field number. +// +// Clear is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_Params) Clear(fd protoreflect.FieldDescriptor) { + switch fd.FullName() { + case "ucallback.v1.Params.some_value": + x.SomeValue = false + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.Params")) + } + panic(fmt.Errorf("message ucallback.v1.Params does not contain field %s", fd.FullName())) + } +} + +// Get retrieves the value for a field. +// +// For unpopulated scalars, it returns the default value, where +// the default value of a bytes scalar is guaranteed to be a copy. +// For unpopulated composite types, it returns an empty, read-only view +// of the value; to obtain a mutable reference, use Mutable. +func (x *fastReflection_Params) Get(descriptor protoreflect.FieldDescriptor) protoreflect.Value { + switch descriptor.FullName() { + case "ucallback.v1.Params.some_value": + value := x.SomeValue + return protoreflect.ValueOfBool(value) + default: + if descriptor.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.Params")) + } + panic(fmt.Errorf("message ucallback.v1.Params does not contain field %s", descriptor.FullName())) + } +} + +// Set stores the value for a field. +// +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType. +// When setting a composite type, it is unspecified whether the stored value +// aliases the source's memory in any way. If the composite value is an +// empty, read-only value, then it panics. +// +// Set is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_Params) Set(fd protoreflect.FieldDescriptor, value protoreflect.Value) { + switch fd.FullName() { + case "ucallback.v1.Params.some_value": + x.SomeValue = value.Bool() + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.Params")) + } + panic(fmt.Errorf("message ucallback.v1.Params does not contain field %s", fd.FullName())) + } +} + +// Mutable returns a mutable reference to a composite type. +// +// If the field is unpopulated, it may allocate a composite value. +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType +// if not already stored. +// It panics if the field does not contain a composite type. +// +// Mutable is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_Params) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "ucallback.v1.Params.some_value": + panic(fmt.Errorf("field some_value of message ucallback.v1.Params is not mutable")) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.Params")) + } + panic(fmt.Errorf("message ucallback.v1.Params does not contain field %s", fd.FullName())) + } +} + +// NewField returns a new value that is assignable to the field +// for the given descriptor. For scalars, this returns the default value. +// For lists, maps, and messages, this returns a new, empty, mutable value. +func (x *fastReflection_Params) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "ucallback.v1.Params.some_value": + return protoreflect.ValueOfBool(false) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.Params")) + } + panic(fmt.Errorf("message ucallback.v1.Params does not contain field %s", fd.FullName())) + } +} + +// WhichOneof reports which field within the oneof is populated, +// returning nil if none are populated. +// It panics if the oneof descriptor does not belong to this message. +func (x *fastReflection_Params) WhichOneof(d protoreflect.OneofDescriptor) protoreflect.FieldDescriptor { + switch d.FullName() { + default: + panic(fmt.Errorf("%s is not a oneof field in ucallback.v1.Params", d.FullName())) + } + panic("unreachable") +} + +// GetUnknown retrieves the entire list of unknown fields. +// The caller may only mutate the contents of the RawFields +// if the mutated bytes are stored back into the message with SetUnknown. +func (x *fastReflection_Params) GetUnknown() protoreflect.RawFields { + return x.unknownFields +} + +// SetUnknown stores an entire list of unknown fields. +// The raw fields must be syntactically valid according to the wire format. +// An implementation may panic if this is not the case. +// Once stored, the caller must not mutate the content of the RawFields. +// An empty RawFields may be passed to clear the fields. +// +// SetUnknown is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_Params) SetUnknown(fields protoreflect.RawFields) { + x.unknownFields = fields +} + +// IsValid reports whether the message is valid. +// +// An invalid message is an empty, read-only value. +// +// An invalid message often corresponds to a nil pointer of the concrete +// message type, but the details are implementation dependent. +// Validity is not part of the protobuf data model, and may not +// be preserved in marshaling or other operations. +func (x *fastReflection_Params) IsValid() bool { + return x != nil +} + +// ProtoMethods returns optional fastReflectionFeature-path implementations of various operations. +// This method may return nil. +// +// The returned methods type is identical to +// "google.golang.org/protobuf/runtime/protoiface".Methods. +// Consult the protoiface package documentation for details. +func (x *fastReflection_Params) ProtoMethods() *protoiface.Methods { + size := func(input protoiface.SizeInput) protoiface.SizeOutput { + x := input.Message.Interface().(*Params) + if x == nil { + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: 0, + } + } + options := runtime.SizeInputToOptions(input) + _ = options + var n int + var l int + _ = l + if x.SomeValue { + n += 2 + } + if x.unknownFields != nil { + n += len(x.unknownFields) + } + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: n, + } + } + + marshal := func(input protoiface.MarshalInput) (protoiface.MarshalOutput, error) { + x := input.Message.Interface().(*Params) + if x == nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + options := runtime.MarshalInputToOptions(input) + _ = options + size := options.Size(x) + dAtA := make([]byte, size) + i := len(dAtA) + _ = i + var l int + _ = l + if x.unknownFields != nil { + i -= len(x.unknownFields) + copy(dAtA[i:], x.unknownFields) + } + if x.SomeValue { + i-- + if x.SomeValue { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x10 + } + if input.Buf != nil { + input.Buf = append(input.Buf, dAtA...) + } else { + input.Buf = dAtA + } + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + unmarshal := func(input protoiface.UnmarshalInput) (protoiface.UnmarshalOutput, error) { + x := input.Message.Interface().(*Params) + if x == nil { + return protoiface.UnmarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Flags: input.Flags, + }, nil + } + options := runtime.UnmarshalInputToOptions(input) + _ = options + dAtA := input.Buf + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: Params: wiretype end group for non-group") + } + if fieldNum <= 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: Params: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 2: + if wireType != 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field SomeValue", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + x.SomeValue = bool(v != 0) + default: + iNdEx = preIndex + skippy, err := runtime.Skip(dAtA[iNdEx:]) + if err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if !options.DiscardUnknown { + x.unknownFields = append(x.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + } + iNdEx += skippy + } + } + + if iNdEx > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, nil + } + return &protoiface.Methods{ + NoUnkeyedLiterals: struct{}{}, + Flags: protoiface.SupportMarshalDeterministic | protoiface.SupportUnmarshalDiscardUnknown, + Size: size, + Marshal: marshal, + Unmarshal: unmarshal, + Merge: nil, + CheckInitialized: nil, + } +} + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.27.0 +// protoc (unknown) +// source: ucallback/v1/genesis.proto + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// GenesisState defines the module genesis state +type GenesisState struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Params defines all the parameters of the module. + Params *Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params,omitempty"` + // universal_reads are key-value pairs from the UniversalReads map. + // + // Only the canonical records are exported. PendingByExpiry and ReadsByTxHash + // are indexes derived from these, and are rebuilt during InitGenesis rather + // than exported — so they cannot be imported out of sync with the records they + // point at. + UniversalReads []*UniversalReadEntry `protobuf:"bytes,2,rep,name=universal_reads,json=universalReads,proto3" json:"universal_reads,omitempty"` + // module_account_nonce is the EVM nonce of the x/ucallback module account. + // + // Must round-trip through genesis: it is the nonce of a real EVM account, and + // exporting state without it would make every module call after an import reuse + // nonces the chain had already consumed. + ModuleAccountNonce uint64 `protobuf:"varint,3,opt,name=module_account_nonce,json=moduleAccountNonce,proto3" json:"module_account_nonce,omitempty"` +} + +func (x *GenesisState) Reset() { + *x = GenesisState{} + if protoimpl.UnsafeEnabled { + mi := &file_ucallback_v1_genesis_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GenesisState) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GenesisState) ProtoMessage() {} + +// Deprecated: Use GenesisState.ProtoReflect.Descriptor instead. +func (*GenesisState) Descriptor() ([]byte, []int) { + return file_ucallback_v1_genesis_proto_rawDescGZIP(), []int{0} +} + +func (x *GenesisState) GetParams() *Params { + if x != nil { + return x.Params + } + return nil +} + +func (x *GenesisState) GetUniversalReads() []*UniversalReadEntry { + if x != nil { + return x.UniversalReads + } + return nil +} + +func (x *GenesisState) GetModuleAccountNonce() uint64 { + if x != nil { + return x.ModuleAccountNonce + } + return 0 +} + +// UniversalReadEntry is one key-value pair from the UniversalReads map. +type UniversalReadEntry struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` + Value *UniversalRead `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"` +} + +func (x *UniversalReadEntry) Reset() { + *x = UniversalReadEntry{} + if protoimpl.UnsafeEnabled { + mi := &file_ucallback_v1_genesis_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UniversalReadEntry) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UniversalReadEntry) ProtoMessage() {} + +// Deprecated: Use UniversalReadEntry.ProtoReflect.Descriptor instead. +func (*UniversalReadEntry) Descriptor() ([]byte, []int) { + return file_ucallback_v1_genesis_proto_rawDescGZIP(), []int{1} +} + +func (x *UniversalReadEntry) GetKey() string { + if x != nil { + return x.Key + } + return "" +} + +func (x *UniversalReadEntry) GetValue() *UniversalRead { + if x != nil { + return x.Value + } + return nil +} + +// Params defines the set of module parameters. +type Params struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + SomeValue bool `protobuf:"varint,2,opt,name=some_value,json=someValue,proto3" json:"some_value,omitempty"` +} + +func (x *Params) Reset() { + *x = Params{} + if protoimpl.UnsafeEnabled { + mi := &file_ucallback_v1_genesis_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Params) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Params) ProtoMessage() {} + +// Deprecated: Use Params.ProtoReflect.Descriptor instead. +func (*Params) Descriptor() ([]byte, []int) { + return file_ucallback_v1_genesis_proto_rawDescGZIP(), []int{2} +} + +func (x *Params) GetSomeValue() bool { + if x != nil { + return x.SomeValue + } + return false +} + +var File_ucallback_v1_genesis_proto protoreflect.FileDescriptor + +var file_ucallback_v1_genesis_proto_rawDesc = []byte{ + 0x0a, 0x1a, 0x75, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x2f, 0x76, 0x31, 0x2f, 0x67, + 0x65, 0x6e, 0x65, 0x73, 0x69, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0c, 0x75, 0x63, + 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x2e, 0x76, 0x31, 0x1a, 0x14, 0x67, 0x6f, 0x67, 0x6f, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x67, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x1a, 0x11, 0x61, 0x6d, 0x69, 0x6e, 0x6f, 0x2f, 0x61, 0x6d, 0x69, 0x6e, 0x6f, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x1a, 0x18, 0x75, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x2f, 0x76, + 0x31, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xc5, 0x01, + 0x0a, 0x0c, 0x47, 0x65, 0x6e, 0x65, 0x73, 0x69, 0x73, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x32, + 0x0a, 0x06, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, + 0x2e, 0x75, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x61, + 0x72, 0x61, 0x6d, 0x73, 0x42, 0x04, 0xc8, 0xde, 0x1f, 0x00, 0x52, 0x06, 0x70, 0x61, 0x72, 0x61, + 0x6d, 0x73, 0x12, 0x4f, 0x0a, 0x0f, 0x75, 0x6e, 0x69, 0x76, 0x65, 0x72, 0x73, 0x61, 0x6c, 0x5f, + 0x72, 0x65, 0x61, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x75, 0x63, + 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x6e, 0x69, 0x76, 0x65, + 0x72, 0x73, 0x61, 0x6c, 0x52, 0x65, 0x61, 0x64, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x42, 0x04, 0xc8, + 0xde, 0x1f, 0x00, 0x52, 0x0e, 0x75, 0x6e, 0x69, 0x76, 0x65, 0x72, 0x73, 0x61, 0x6c, 0x52, 0x65, + 0x61, 0x64, 0x73, 0x12, 0x30, 0x0a, 0x14, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x61, 0x63, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x04, 0x52, 0x12, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, + 0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x22, 0x5f, 0x0a, 0x12, 0x55, 0x6e, 0x69, 0x76, 0x65, 0x72, 0x73, + 0x61, 0x6c, 0x52, 0x65, 0x61, 0x64, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, + 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x37, 0x0a, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x75, + 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x6e, 0x69, 0x76, + 0x65, 0x72, 0x73, 0x61, 0x6c, 0x52, 0x65, 0x61, 0x64, 0x42, 0x04, 0xc8, 0xde, 0x1f, 0x00, 0x52, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x46, 0x0a, 0x06, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, + 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x6f, 0x6d, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x73, 0x6f, 0x6d, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x3a, + 0x1d, 0x98, 0xa0, 0x1f, 0x00, 0xe8, 0xa0, 0x1f, 0x01, 0x8a, 0xe7, 0xb0, 0x2a, 0x10, 0x75, 0x63, + 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x2f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x42, 0xb4, + 0x01, 0x0a, 0x10, 0x63, 0x6f, 0x6d, 0x2e, 0x75, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, + 0x2e, 0x76, 0x31, 0x42, 0x0c, 0x47, 0x65, 0x6e, 0x65, 0x73, 0x69, 0x73, 0x50, 0x72, 0x6f, 0x74, + 0x6f, 0x50, 0x01, 0x5a, 0x41, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, + 0x70, 0x75, 0x73, 0x68, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x2f, 0x70, 0x75, 0x73, 0x68, 0x2d, 0x63, + 0x68, 0x61, 0x69, 0x6e, 0x2d, 0x6e, 0x6f, 0x64, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x75, 0x63, + 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x2f, 0x76, 0x31, 0x3b, 0x75, 0x63, 0x61, 0x6c, 0x6c, + 0x62, 0x61, 0x63, 0x6b, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x55, 0x58, 0x58, 0xaa, 0x02, 0x0c, 0x55, + 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x0c, 0x55, 0x63, + 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x18, 0x55, 0x63, 0x61, + 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, + 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0d, 0x55, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, + 0x6b, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_ucallback_v1_genesis_proto_rawDescOnce sync.Once + file_ucallback_v1_genesis_proto_rawDescData = file_ucallback_v1_genesis_proto_rawDesc +) + +func file_ucallback_v1_genesis_proto_rawDescGZIP() []byte { + file_ucallback_v1_genesis_proto_rawDescOnce.Do(func() { + file_ucallback_v1_genesis_proto_rawDescData = protoimpl.X.CompressGZIP(file_ucallback_v1_genesis_proto_rawDescData) + }) + return file_ucallback_v1_genesis_proto_rawDescData +} + +var file_ucallback_v1_genesis_proto_msgTypes = make([]protoimpl.MessageInfo, 3) +var file_ucallback_v1_genesis_proto_goTypes = []interface{}{ + (*GenesisState)(nil), // 0: ucallback.v1.GenesisState + (*UniversalReadEntry)(nil), // 1: ucallback.v1.UniversalReadEntry + (*Params)(nil), // 2: ucallback.v1.Params + (*UniversalRead)(nil), // 3: ucallback.v1.UniversalRead +} +var file_ucallback_v1_genesis_proto_depIdxs = []int32{ + 2, // 0: ucallback.v1.GenesisState.params:type_name -> ucallback.v1.Params + 1, // 1: ucallback.v1.GenesisState.universal_reads:type_name -> ucallback.v1.UniversalReadEntry + 3, // 2: ucallback.v1.UniversalReadEntry.value:type_name -> ucallback.v1.UniversalRead + 3, // [3:3] is the sub-list for method output_type + 3, // [3:3] is the sub-list for method input_type + 3, // [3:3] is the sub-list for extension type_name + 3, // [3:3] is the sub-list for extension extendee + 0, // [0:3] is the sub-list for field type_name +} + +func init() { file_ucallback_v1_genesis_proto_init() } +func file_ucallback_v1_genesis_proto_init() { + if File_ucallback_v1_genesis_proto != nil { + return + } + file_ucallback_v1_types_proto_init() + if !protoimpl.UnsafeEnabled { + file_ucallback_v1_genesis_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GenesisState); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ucallback_v1_genesis_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UniversalReadEntry); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ucallback_v1_genesis_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Params); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_ucallback_v1_genesis_proto_rawDesc, + NumEnums: 0, + NumMessages: 3, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_ucallback_v1_genesis_proto_goTypes, + DependencyIndexes: file_ucallback_v1_genesis_proto_depIdxs, + MessageInfos: file_ucallback_v1_genesis_proto_msgTypes, + }.Build() + File_ucallback_v1_genesis_proto = out.File + file_ucallback_v1_genesis_proto_rawDesc = nil + file_ucallback_v1_genesis_proto_goTypes = nil + file_ucallback_v1_genesis_proto_depIdxs = nil +} diff --git a/api/ucallback/v1/query.pulsar.go b/api/ucallback/v1/query.pulsar.go new file mode 100644 index 00000000..1e0c23f2 --- /dev/null +++ b/api/ucallback/v1/query.pulsar.go @@ -0,0 +1,5309 @@ +// Code generated by protoc-gen-go-pulsar. DO NOT EDIT. +package ucallbackv1 + +import ( + v1beta1 "cosmossdk.io/api/cosmos/base/query/v1beta1" + fmt "fmt" + runtime "github.com/cosmos/cosmos-proto/runtime" + _ "github.com/cosmos/gogoproto/gogoproto" + _ "google.golang.org/genproto/googleapis/api/annotations" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoiface "google.golang.org/protobuf/runtime/protoiface" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" +) + +var ( + md_QueryParamsRequest protoreflect.MessageDescriptor +) + +func init() { + file_ucallback_v1_query_proto_init() + md_QueryParamsRequest = File_ucallback_v1_query_proto.Messages().ByName("QueryParamsRequest") +} + +var _ protoreflect.Message = (*fastReflection_QueryParamsRequest)(nil) + +type fastReflection_QueryParamsRequest QueryParamsRequest + +func (x *QueryParamsRequest) ProtoReflect() protoreflect.Message { + return (*fastReflection_QueryParamsRequest)(x) +} + +func (x *QueryParamsRequest) slowProtoReflect() protoreflect.Message { + mi := &file_ucallback_v1_query_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +var _fastReflection_QueryParamsRequest_messageType fastReflection_QueryParamsRequest_messageType +var _ protoreflect.MessageType = fastReflection_QueryParamsRequest_messageType{} + +type fastReflection_QueryParamsRequest_messageType struct{} + +func (x fastReflection_QueryParamsRequest_messageType) Zero() protoreflect.Message { + return (*fastReflection_QueryParamsRequest)(nil) +} +func (x fastReflection_QueryParamsRequest_messageType) New() protoreflect.Message { + return new(fastReflection_QueryParamsRequest) +} +func (x fastReflection_QueryParamsRequest_messageType) Descriptor() protoreflect.MessageDescriptor { + return md_QueryParamsRequest +} + +// Descriptor returns message descriptor, which contains only the protobuf +// type information for the message. +func (x *fastReflection_QueryParamsRequest) Descriptor() protoreflect.MessageDescriptor { + return md_QueryParamsRequest +} + +// Type returns the message type, which encapsulates both Go and protobuf +// type information. If the Go type information is not needed, +// it is recommended that the message descriptor be used instead. +func (x *fastReflection_QueryParamsRequest) Type() protoreflect.MessageType { + return _fastReflection_QueryParamsRequest_messageType +} + +// New returns a newly allocated and mutable empty message. +func (x *fastReflection_QueryParamsRequest) New() protoreflect.Message { + return new(fastReflection_QueryParamsRequest) +} + +// Interface unwraps the message reflection interface and +// returns the underlying ProtoMessage interface. +func (x *fastReflection_QueryParamsRequest) Interface() protoreflect.ProtoMessage { + return (*QueryParamsRequest)(x) +} + +// Range iterates over every populated field in an undefined order, +// calling f for each field descriptor and value encountered. +// Range returns immediately if f returns false. +// While iterating, mutating operations may only be performed +// on the current field descriptor. +func (x *fastReflection_QueryParamsRequest) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { +} + +// Has reports whether a field is populated. +// +// Some fields have the property of nullability where it is possible to +// distinguish between the default value of a field and whether the field +// was explicitly populated with the default value. Singular message fields, +// member fields of a oneof, and proto2 scalar fields are nullable. Such +// fields are populated only if explicitly set. +// +// In other cases (aside from the nullable cases above), +// a proto3 scalar field is populated if it contains a non-zero value, and +// a repeated field is populated if it is non-empty. +func (x *fastReflection_QueryParamsRequest) Has(fd protoreflect.FieldDescriptor) bool { + switch fd.FullName() { + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.QueryParamsRequest")) + } + panic(fmt.Errorf("message ucallback.v1.QueryParamsRequest does not contain field %s", fd.FullName())) + } +} + +// Clear clears the field such that a subsequent Has call reports false. +// +// Clearing an extension field clears both the extension type and value +// associated with the given field number. +// +// Clear is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_QueryParamsRequest) Clear(fd protoreflect.FieldDescriptor) { + switch fd.FullName() { + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.QueryParamsRequest")) + } + panic(fmt.Errorf("message ucallback.v1.QueryParamsRequest does not contain field %s", fd.FullName())) + } +} + +// Get retrieves the value for a field. +// +// For unpopulated scalars, it returns the default value, where +// the default value of a bytes scalar is guaranteed to be a copy. +// For unpopulated composite types, it returns an empty, read-only view +// of the value; to obtain a mutable reference, use Mutable. +func (x *fastReflection_QueryParamsRequest) Get(descriptor protoreflect.FieldDescriptor) protoreflect.Value { + switch descriptor.FullName() { + default: + if descriptor.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.QueryParamsRequest")) + } + panic(fmt.Errorf("message ucallback.v1.QueryParamsRequest does not contain field %s", descriptor.FullName())) + } +} + +// Set stores the value for a field. +// +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType. +// When setting a composite type, it is unspecified whether the stored value +// aliases the source's memory in any way. If the composite value is an +// empty, read-only value, then it panics. +// +// Set is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_QueryParamsRequest) Set(fd protoreflect.FieldDescriptor, value protoreflect.Value) { + switch fd.FullName() { + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.QueryParamsRequest")) + } + panic(fmt.Errorf("message ucallback.v1.QueryParamsRequest does not contain field %s", fd.FullName())) + } +} + +// Mutable returns a mutable reference to a composite type. +// +// If the field is unpopulated, it may allocate a composite value. +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType +// if not already stored. +// It panics if the field does not contain a composite type. +// +// Mutable is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_QueryParamsRequest) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.QueryParamsRequest")) + } + panic(fmt.Errorf("message ucallback.v1.QueryParamsRequest does not contain field %s", fd.FullName())) + } +} + +// NewField returns a new value that is assignable to the field +// for the given descriptor. For scalars, this returns the default value. +// For lists, maps, and messages, this returns a new, empty, mutable value. +func (x *fastReflection_QueryParamsRequest) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.QueryParamsRequest")) + } + panic(fmt.Errorf("message ucallback.v1.QueryParamsRequest does not contain field %s", fd.FullName())) + } +} + +// WhichOneof reports which field within the oneof is populated, +// returning nil if none are populated. +// It panics if the oneof descriptor does not belong to this message. +func (x *fastReflection_QueryParamsRequest) WhichOneof(d protoreflect.OneofDescriptor) protoreflect.FieldDescriptor { + switch d.FullName() { + default: + panic(fmt.Errorf("%s is not a oneof field in ucallback.v1.QueryParamsRequest", d.FullName())) + } + panic("unreachable") +} + +// GetUnknown retrieves the entire list of unknown fields. +// The caller may only mutate the contents of the RawFields +// if the mutated bytes are stored back into the message with SetUnknown. +func (x *fastReflection_QueryParamsRequest) GetUnknown() protoreflect.RawFields { + return x.unknownFields +} + +// SetUnknown stores an entire list of unknown fields. +// The raw fields must be syntactically valid according to the wire format. +// An implementation may panic if this is not the case. +// Once stored, the caller must not mutate the content of the RawFields. +// An empty RawFields may be passed to clear the fields. +// +// SetUnknown is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_QueryParamsRequest) SetUnknown(fields protoreflect.RawFields) { + x.unknownFields = fields +} + +// IsValid reports whether the message is valid. +// +// An invalid message is an empty, read-only value. +// +// An invalid message often corresponds to a nil pointer of the concrete +// message type, but the details are implementation dependent. +// Validity is not part of the protobuf data model, and may not +// be preserved in marshaling or other operations. +func (x *fastReflection_QueryParamsRequest) IsValid() bool { + return x != nil +} + +// ProtoMethods returns optional fastReflectionFeature-path implementations of various operations. +// This method may return nil. +// +// The returned methods type is identical to +// "google.golang.org/protobuf/runtime/protoiface".Methods. +// Consult the protoiface package documentation for details. +func (x *fastReflection_QueryParamsRequest) ProtoMethods() *protoiface.Methods { + size := func(input protoiface.SizeInput) protoiface.SizeOutput { + x := input.Message.Interface().(*QueryParamsRequest) + if x == nil { + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: 0, + } + } + options := runtime.SizeInputToOptions(input) + _ = options + var n int + var l int + _ = l + if x.unknownFields != nil { + n += len(x.unknownFields) + } + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: n, + } + } + + marshal := func(input protoiface.MarshalInput) (protoiface.MarshalOutput, error) { + x := input.Message.Interface().(*QueryParamsRequest) + if x == nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + options := runtime.MarshalInputToOptions(input) + _ = options + size := options.Size(x) + dAtA := make([]byte, size) + i := len(dAtA) + _ = i + var l int + _ = l + if x.unknownFields != nil { + i -= len(x.unknownFields) + copy(dAtA[i:], x.unknownFields) + } + if input.Buf != nil { + input.Buf = append(input.Buf, dAtA...) + } else { + input.Buf = dAtA + } + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + unmarshal := func(input protoiface.UnmarshalInput) (protoiface.UnmarshalOutput, error) { + x := input.Message.Interface().(*QueryParamsRequest) + if x == nil { + return protoiface.UnmarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Flags: input.Flags, + }, nil + } + options := runtime.UnmarshalInputToOptions(input) + _ = options + dAtA := input.Buf + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: QueryParamsRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: QueryParamsRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := runtime.Skip(dAtA[iNdEx:]) + if err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if !options.DiscardUnknown { + x.unknownFields = append(x.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + } + iNdEx += skippy + } + } + + if iNdEx > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, nil + } + return &protoiface.Methods{ + NoUnkeyedLiterals: struct{}{}, + Flags: protoiface.SupportMarshalDeterministic | protoiface.SupportUnmarshalDiscardUnknown, + Size: size, + Marshal: marshal, + Unmarshal: unmarshal, + Merge: nil, + CheckInitialized: nil, + } +} + +var ( + md_QueryParamsResponse protoreflect.MessageDescriptor + fd_QueryParamsResponse_params protoreflect.FieldDescriptor +) + +func init() { + file_ucallback_v1_query_proto_init() + md_QueryParamsResponse = File_ucallback_v1_query_proto.Messages().ByName("QueryParamsResponse") + fd_QueryParamsResponse_params = md_QueryParamsResponse.Fields().ByName("params") +} + +var _ protoreflect.Message = (*fastReflection_QueryParamsResponse)(nil) + +type fastReflection_QueryParamsResponse QueryParamsResponse + +func (x *QueryParamsResponse) ProtoReflect() protoreflect.Message { + return (*fastReflection_QueryParamsResponse)(x) +} + +func (x *QueryParamsResponse) slowProtoReflect() protoreflect.Message { + mi := &file_ucallback_v1_query_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +var _fastReflection_QueryParamsResponse_messageType fastReflection_QueryParamsResponse_messageType +var _ protoreflect.MessageType = fastReflection_QueryParamsResponse_messageType{} + +type fastReflection_QueryParamsResponse_messageType struct{} + +func (x fastReflection_QueryParamsResponse_messageType) Zero() protoreflect.Message { + return (*fastReflection_QueryParamsResponse)(nil) +} +func (x fastReflection_QueryParamsResponse_messageType) New() protoreflect.Message { + return new(fastReflection_QueryParamsResponse) +} +func (x fastReflection_QueryParamsResponse_messageType) Descriptor() protoreflect.MessageDescriptor { + return md_QueryParamsResponse +} + +// Descriptor returns message descriptor, which contains only the protobuf +// type information for the message. +func (x *fastReflection_QueryParamsResponse) Descriptor() protoreflect.MessageDescriptor { + return md_QueryParamsResponse +} + +// Type returns the message type, which encapsulates both Go and protobuf +// type information. If the Go type information is not needed, +// it is recommended that the message descriptor be used instead. +func (x *fastReflection_QueryParamsResponse) Type() protoreflect.MessageType { + return _fastReflection_QueryParamsResponse_messageType +} + +// New returns a newly allocated and mutable empty message. +func (x *fastReflection_QueryParamsResponse) New() protoreflect.Message { + return new(fastReflection_QueryParamsResponse) +} + +// Interface unwraps the message reflection interface and +// returns the underlying ProtoMessage interface. +func (x *fastReflection_QueryParamsResponse) Interface() protoreflect.ProtoMessage { + return (*QueryParamsResponse)(x) +} + +// Range iterates over every populated field in an undefined order, +// calling f for each field descriptor and value encountered. +// Range returns immediately if f returns false. +// While iterating, mutating operations may only be performed +// on the current field descriptor. +func (x *fastReflection_QueryParamsResponse) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { + if x.Params != nil { + value := protoreflect.ValueOfMessage(x.Params.ProtoReflect()) + if !f(fd_QueryParamsResponse_params, value) { + return + } + } +} + +// Has reports whether a field is populated. +// +// Some fields have the property of nullability where it is possible to +// distinguish between the default value of a field and whether the field +// was explicitly populated with the default value. Singular message fields, +// member fields of a oneof, and proto2 scalar fields are nullable. Such +// fields are populated only if explicitly set. +// +// In other cases (aside from the nullable cases above), +// a proto3 scalar field is populated if it contains a non-zero value, and +// a repeated field is populated if it is non-empty. +func (x *fastReflection_QueryParamsResponse) Has(fd protoreflect.FieldDescriptor) bool { + switch fd.FullName() { + case "ucallback.v1.QueryParamsResponse.params": + return x.Params != nil + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.QueryParamsResponse")) + } + panic(fmt.Errorf("message ucallback.v1.QueryParamsResponse does not contain field %s", fd.FullName())) + } +} + +// Clear clears the field such that a subsequent Has call reports false. +// +// Clearing an extension field clears both the extension type and value +// associated with the given field number. +// +// Clear is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_QueryParamsResponse) Clear(fd protoreflect.FieldDescriptor) { + switch fd.FullName() { + case "ucallback.v1.QueryParamsResponse.params": + x.Params = nil + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.QueryParamsResponse")) + } + panic(fmt.Errorf("message ucallback.v1.QueryParamsResponse does not contain field %s", fd.FullName())) + } +} + +// Get retrieves the value for a field. +// +// For unpopulated scalars, it returns the default value, where +// the default value of a bytes scalar is guaranteed to be a copy. +// For unpopulated composite types, it returns an empty, read-only view +// of the value; to obtain a mutable reference, use Mutable. +func (x *fastReflection_QueryParamsResponse) Get(descriptor protoreflect.FieldDescriptor) protoreflect.Value { + switch descriptor.FullName() { + case "ucallback.v1.QueryParamsResponse.params": + value := x.Params + return protoreflect.ValueOfMessage(value.ProtoReflect()) + default: + if descriptor.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.QueryParamsResponse")) + } + panic(fmt.Errorf("message ucallback.v1.QueryParamsResponse does not contain field %s", descriptor.FullName())) + } +} + +// Set stores the value for a field. +// +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType. +// When setting a composite type, it is unspecified whether the stored value +// aliases the source's memory in any way. If the composite value is an +// empty, read-only value, then it panics. +// +// Set is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_QueryParamsResponse) Set(fd protoreflect.FieldDescriptor, value protoreflect.Value) { + switch fd.FullName() { + case "ucallback.v1.QueryParamsResponse.params": + x.Params = value.Message().Interface().(*Params) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.QueryParamsResponse")) + } + panic(fmt.Errorf("message ucallback.v1.QueryParamsResponse does not contain field %s", fd.FullName())) + } +} + +// Mutable returns a mutable reference to a composite type. +// +// If the field is unpopulated, it may allocate a composite value. +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType +// if not already stored. +// It panics if the field does not contain a composite type. +// +// Mutable is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_QueryParamsResponse) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "ucallback.v1.QueryParamsResponse.params": + if x.Params == nil { + x.Params = new(Params) + } + return protoreflect.ValueOfMessage(x.Params.ProtoReflect()) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.QueryParamsResponse")) + } + panic(fmt.Errorf("message ucallback.v1.QueryParamsResponse does not contain field %s", fd.FullName())) + } +} + +// NewField returns a new value that is assignable to the field +// for the given descriptor. For scalars, this returns the default value. +// For lists, maps, and messages, this returns a new, empty, mutable value. +func (x *fastReflection_QueryParamsResponse) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "ucallback.v1.QueryParamsResponse.params": + m := new(Params) + return protoreflect.ValueOfMessage(m.ProtoReflect()) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.QueryParamsResponse")) + } + panic(fmt.Errorf("message ucallback.v1.QueryParamsResponse does not contain field %s", fd.FullName())) + } +} + +// WhichOneof reports which field within the oneof is populated, +// returning nil if none are populated. +// It panics if the oneof descriptor does not belong to this message. +func (x *fastReflection_QueryParamsResponse) WhichOneof(d protoreflect.OneofDescriptor) protoreflect.FieldDescriptor { + switch d.FullName() { + default: + panic(fmt.Errorf("%s is not a oneof field in ucallback.v1.QueryParamsResponse", d.FullName())) + } + panic("unreachable") +} + +// GetUnknown retrieves the entire list of unknown fields. +// The caller may only mutate the contents of the RawFields +// if the mutated bytes are stored back into the message with SetUnknown. +func (x *fastReflection_QueryParamsResponse) GetUnknown() protoreflect.RawFields { + return x.unknownFields +} + +// SetUnknown stores an entire list of unknown fields. +// The raw fields must be syntactically valid according to the wire format. +// An implementation may panic if this is not the case. +// Once stored, the caller must not mutate the content of the RawFields. +// An empty RawFields may be passed to clear the fields. +// +// SetUnknown is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_QueryParamsResponse) SetUnknown(fields protoreflect.RawFields) { + x.unknownFields = fields +} + +// IsValid reports whether the message is valid. +// +// An invalid message is an empty, read-only value. +// +// An invalid message often corresponds to a nil pointer of the concrete +// message type, but the details are implementation dependent. +// Validity is not part of the protobuf data model, and may not +// be preserved in marshaling or other operations. +func (x *fastReflection_QueryParamsResponse) IsValid() bool { + return x != nil +} + +// ProtoMethods returns optional fastReflectionFeature-path implementations of various operations. +// This method may return nil. +// +// The returned methods type is identical to +// "google.golang.org/protobuf/runtime/protoiface".Methods. +// Consult the protoiface package documentation for details. +func (x *fastReflection_QueryParamsResponse) ProtoMethods() *protoiface.Methods { + size := func(input protoiface.SizeInput) protoiface.SizeOutput { + x := input.Message.Interface().(*QueryParamsResponse) + if x == nil { + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: 0, + } + } + options := runtime.SizeInputToOptions(input) + _ = options + var n int + var l int + _ = l + if x.Params != nil { + l = options.Size(x.Params) + n += 1 + l + runtime.Sov(uint64(l)) + } + if x.unknownFields != nil { + n += len(x.unknownFields) + } + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: n, + } + } + + marshal := func(input protoiface.MarshalInput) (protoiface.MarshalOutput, error) { + x := input.Message.Interface().(*QueryParamsResponse) + if x == nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + options := runtime.MarshalInputToOptions(input) + _ = options + size := options.Size(x) + dAtA := make([]byte, size) + i := len(dAtA) + _ = i + var l int + _ = l + if x.unknownFields != nil { + i -= len(x.unknownFields) + copy(dAtA[i:], x.unknownFields) + } + if x.Params != nil { + encoded, err := options.Marshal(x.Params) + if err != nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, err + } + i -= len(encoded) + copy(dAtA[i:], encoded) + i = runtime.EncodeVarint(dAtA, i, uint64(len(encoded))) + i-- + dAtA[i] = 0xa + } + if input.Buf != nil { + input.Buf = append(input.Buf, dAtA...) + } else { + input.Buf = dAtA + } + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + unmarshal := func(input protoiface.UnmarshalInput) (protoiface.UnmarshalOutput, error) { + x := input.Message.Interface().(*QueryParamsResponse) + if x == nil { + return protoiface.UnmarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Flags: input.Flags, + }, nil + } + options := runtime.UnmarshalInputToOptions(input) + _ = options + dAtA := input.Buf + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: QueryParamsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: QueryParamsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Params", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if x.Params == nil { + x.Params = &Params{} + } + if err := options.Unmarshal(dAtA[iNdEx:postIndex], x.Params); err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := runtime.Skip(dAtA[iNdEx:]) + if err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if !options.DiscardUnknown { + x.unknownFields = append(x.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + } + iNdEx += skippy + } + } + + if iNdEx > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, nil + } + return &protoiface.Methods{ + NoUnkeyedLiterals: struct{}{}, + Flags: protoiface.SupportMarshalDeterministic | protoiface.SupportUnmarshalDiscardUnknown, + Size: size, + Marshal: marshal, + Unmarshal: unmarshal, + Merge: nil, + CheckInitialized: nil, + } +} + +var ( + md_QueryAllPendingReadRequestsRequest protoreflect.MessageDescriptor + fd_QueryAllPendingReadRequestsRequest_pagination protoreflect.FieldDescriptor +) + +func init() { + file_ucallback_v1_query_proto_init() + md_QueryAllPendingReadRequestsRequest = File_ucallback_v1_query_proto.Messages().ByName("QueryAllPendingReadRequestsRequest") + fd_QueryAllPendingReadRequestsRequest_pagination = md_QueryAllPendingReadRequestsRequest.Fields().ByName("pagination") +} + +var _ protoreflect.Message = (*fastReflection_QueryAllPendingReadRequestsRequest)(nil) + +type fastReflection_QueryAllPendingReadRequestsRequest QueryAllPendingReadRequestsRequest + +func (x *QueryAllPendingReadRequestsRequest) ProtoReflect() protoreflect.Message { + return (*fastReflection_QueryAllPendingReadRequestsRequest)(x) +} + +func (x *QueryAllPendingReadRequestsRequest) slowProtoReflect() protoreflect.Message { + mi := &file_ucallback_v1_query_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +var _fastReflection_QueryAllPendingReadRequestsRequest_messageType fastReflection_QueryAllPendingReadRequestsRequest_messageType +var _ protoreflect.MessageType = fastReflection_QueryAllPendingReadRequestsRequest_messageType{} + +type fastReflection_QueryAllPendingReadRequestsRequest_messageType struct{} + +func (x fastReflection_QueryAllPendingReadRequestsRequest_messageType) Zero() protoreflect.Message { + return (*fastReflection_QueryAllPendingReadRequestsRequest)(nil) +} +func (x fastReflection_QueryAllPendingReadRequestsRequest_messageType) New() protoreflect.Message { + return new(fastReflection_QueryAllPendingReadRequestsRequest) +} +func (x fastReflection_QueryAllPendingReadRequestsRequest_messageType) Descriptor() protoreflect.MessageDescriptor { + return md_QueryAllPendingReadRequestsRequest +} + +// Descriptor returns message descriptor, which contains only the protobuf +// type information for the message. +func (x *fastReflection_QueryAllPendingReadRequestsRequest) Descriptor() protoreflect.MessageDescriptor { + return md_QueryAllPendingReadRequestsRequest +} + +// Type returns the message type, which encapsulates both Go and protobuf +// type information. If the Go type information is not needed, +// it is recommended that the message descriptor be used instead. +func (x *fastReflection_QueryAllPendingReadRequestsRequest) Type() protoreflect.MessageType { + return _fastReflection_QueryAllPendingReadRequestsRequest_messageType +} + +// New returns a newly allocated and mutable empty message. +func (x *fastReflection_QueryAllPendingReadRequestsRequest) New() protoreflect.Message { + return new(fastReflection_QueryAllPendingReadRequestsRequest) +} + +// Interface unwraps the message reflection interface and +// returns the underlying ProtoMessage interface. +func (x *fastReflection_QueryAllPendingReadRequestsRequest) Interface() protoreflect.ProtoMessage { + return (*QueryAllPendingReadRequestsRequest)(x) +} + +// Range iterates over every populated field in an undefined order, +// calling f for each field descriptor and value encountered. +// Range returns immediately if f returns false. +// While iterating, mutating operations may only be performed +// on the current field descriptor. +func (x *fastReflection_QueryAllPendingReadRequestsRequest) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { + if x.Pagination != nil { + value := protoreflect.ValueOfMessage(x.Pagination.ProtoReflect()) + if !f(fd_QueryAllPendingReadRequestsRequest_pagination, value) { + return + } + } +} + +// Has reports whether a field is populated. +// +// Some fields have the property of nullability where it is possible to +// distinguish between the default value of a field and whether the field +// was explicitly populated with the default value. Singular message fields, +// member fields of a oneof, and proto2 scalar fields are nullable. Such +// fields are populated only if explicitly set. +// +// In other cases (aside from the nullable cases above), +// a proto3 scalar field is populated if it contains a non-zero value, and +// a repeated field is populated if it is non-empty. +func (x *fastReflection_QueryAllPendingReadRequestsRequest) Has(fd protoreflect.FieldDescriptor) bool { + switch fd.FullName() { + case "ucallback.v1.QueryAllPendingReadRequestsRequest.pagination": + return x.Pagination != nil + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.QueryAllPendingReadRequestsRequest")) + } + panic(fmt.Errorf("message ucallback.v1.QueryAllPendingReadRequestsRequest does not contain field %s", fd.FullName())) + } +} + +// Clear clears the field such that a subsequent Has call reports false. +// +// Clearing an extension field clears both the extension type and value +// associated with the given field number. +// +// Clear is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_QueryAllPendingReadRequestsRequest) Clear(fd protoreflect.FieldDescriptor) { + switch fd.FullName() { + case "ucallback.v1.QueryAllPendingReadRequestsRequest.pagination": + x.Pagination = nil + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.QueryAllPendingReadRequestsRequest")) + } + panic(fmt.Errorf("message ucallback.v1.QueryAllPendingReadRequestsRequest does not contain field %s", fd.FullName())) + } +} + +// Get retrieves the value for a field. +// +// For unpopulated scalars, it returns the default value, where +// the default value of a bytes scalar is guaranteed to be a copy. +// For unpopulated composite types, it returns an empty, read-only view +// of the value; to obtain a mutable reference, use Mutable. +func (x *fastReflection_QueryAllPendingReadRequestsRequest) Get(descriptor protoreflect.FieldDescriptor) protoreflect.Value { + switch descriptor.FullName() { + case "ucallback.v1.QueryAllPendingReadRequestsRequest.pagination": + value := x.Pagination + return protoreflect.ValueOfMessage(value.ProtoReflect()) + default: + if descriptor.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.QueryAllPendingReadRequestsRequest")) + } + panic(fmt.Errorf("message ucallback.v1.QueryAllPendingReadRequestsRequest does not contain field %s", descriptor.FullName())) + } +} + +// Set stores the value for a field. +// +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType. +// When setting a composite type, it is unspecified whether the stored value +// aliases the source's memory in any way. If the composite value is an +// empty, read-only value, then it panics. +// +// Set is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_QueryAllPendingReadRequestsRequest) Set(fd protoreflect.FieldDescriptor, value protoreflect.Value) { + switch fd.FullName() { + case "ucallback.v1.QueryAllPendingReadRequestsRequest.pagination": + x.Pagination = value.Message().Interface().(*v1beta1.PageRequest) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.QueryAllPendingReadRequestsRequest")) + } + panic(fmt.Errorf("message ucallback.v1.QueryAllPendingReadRequestsRequest does not contain field %s", fd.FullName())) + } +} + +// Mutable returns a mutable reference to a composite type. +// +// If the field is unpopulated, it may allocate a composite value. +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType +// if not already stored. +// It panics if the field does not contain a composite type. +// +// Mutable is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_QueryAllPendingReadRequestsRequest) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "ucallback.v1.QueryAllPendingReadRequestsRequest.pagination": + if x.Pagination == nil { + x.Pagination = new(v1beta1.PageRequest) + } + return protoreflect.ValueOfMessage(x.Pagination.ProtoReflect()) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.QueryAllPendingReadRequestsRequest")) + } + panic(fmt.Errorf("message ucallback.v1.QueryAllPendingReadRequestsRequest does not contain field %s", fd.FullName())) + } +} + +// NewField returns a new value that is assignable to the field +// for the given descriptor. For scalars, this returns the default value. +// For lists, maps, and messages, this returns a new, empty, mutable value. +func (x *fastReflection_QueryAllPendingReadRequestsRequest) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "ucallback.v1.QueryAllPendingReadRequestsRequest.pagination": + m := new(v1beta1.PageRequest) + return protoreflect.ValueOfMessage(m.ProtoReflect()) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.QueryAllPendingReadRequestsRequest")) + } + panic(fmt.Errorf("message ucallback.v1.QueryAllPendingReadRequestsRequest does not contain field %s", fd.FullName())) + } +} + +// WhichOneof reports which field within the oneof is populated, +// returning nil if none are populated. +// It panics if the oneof descriptor does not belong to this message. +func (x *fastReflection_QueryAllPendingReadRequestsRequest) WhichOneof(d protoreflect.OneofDescriptor) protoreflect.FieldDescriptor { + switch d.FullName() { + default: + panic(fmt.Errorf("%s is not a oneof field in ucallback.v1.QueryAllPendingReadRequestsRequest", d.FullName())) + } + panic("unreachable") +} + +// GetUnknown retrieves the entire list of unknown fields. +// The caller may only mutate the contents of the RawFields +// if the mutated bytes are stored back into the message with SetUnknown. +func (x *fastReflection_QueryAllPendingReadRequestsRequest) GetUnknown() protoreflect.RawFields { + return x.unknownFields +} + +// SetUnknown stores an entire list of unknown fields. +// The raw fields must be syntactically valid according to the wire format. +// An implementation may panic if this is not the case. +// Once stored, the caller must not mutate the content of the RawFields. +// An empty RawFields may be passed to clear the fields. +// +// SetUnknown is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_QueryAllPendingReadRequestsRequest) SetUnknown(fields protoreflect.RawFields) { + x.unknownFields = fields +} + +// IsValid reports whether the message is valid. +// +// An invalid message is an empty, read-only value. +// +// An invalid message often corresponds to a nil pointer of the concrete +// message type, but the details are implementation dependent. +// Validity is not part of the protobuf data model, and may not +// be preserved in marshaling or other operations. +func (x *fastReflection_QueryAllPendingReadRequestsRequest) IsValid() bool { + return x != nil +} + +// ProtoMethods returns optional fastReflectionFeature-path implementations of various operations. +// This method may return nil. +// +// The returned methods type is identical to +// "google.golang.org/protobuf/runtime/protoiface".Methods. +// Consult the protoiface package documentation for details. +func (x *fastReflection_QueryAllPendingReadRequestsRequest) ProtoMethods() *protoiface.Methods { + size := func(input protoiface.SizeInput) protoiface.SizeOutput { + x := input.Message.Interface().(*QueryAllPendingReadRequestsRequest) + if x == nil { + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: 0, + } + } + options := runtime.SizeInputToOptions(input) + _ = options + var n int + var l int + _ = l + if x.Pagination != nil { + l = options.Size(x.Pagination) + n += 1 + l + runtime.Sov(uint64(l)) + } + if x.unknownFields != nil { + n += len(x.unknownFields) + } + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: n, + } + } + + marshal := func(input protoiface.MarshalInput) (protoiface.MarshalOutput, error) { + x := input.Message.Interface().(*QueryAllPendingReadRequestsRequest) + if x == nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + options := runtime.MarshalInputToOptions(input) + _ = options + size := options.Size(x) + dAtA := make([]byte, size) + i := len(dAtA) + _ = i + var l int + _ = l + if x.unknownFields != nil { + i -= len(x.unknownFields) + copy(dAtA[i:], x.unknownFields) + } + if x.Pagination != nil { + encoded, err := options.Marshal(x.Pagination) + if err != nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, err + } + i -= len(encoded) + copy(dAtA[i:], encoded) + i = runtime.EncodeVarint(dAtA, i, uint64(len(encoded))) + i-- + dAtA[i] = 0xa + } + if input.Buf != nil { + input.Buf = append(input.Buf, dAtA...) + } else { + input.Buf = dAtA + } + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + unmarshal := func(input protoiface.UnmarshalInput) (protoiface.UnmarshalOutput, error) { + x := input.Message.Interface().(*QueryAllPendingReadRequestsRequest) + if x == nil { + return protoiface.UnmarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Flags: input.Flags, + }, nil + } + options := runtime.UnmarshalInputToOptions(input) + _ = options + dAtA := input.Buf + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: QueryAllPendingReadRequestsRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: QueryAllPendingReadRequestsRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Pagination", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if x.Pagination == nil { + x.Pagination = &v1beta1.PageRequest{} + } + if err := options.Unmarshal(dAtA[iNdEx:postIndex], x.Pagination); err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := runtime.Skip(dAtA[iNdEx:]) + if err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if !options.DiscardUnknown { + x.unknownFields = append(x.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + } + iNdEx += skippy + } + } + + if iNdEx > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, nil + } + return &protoiface.Methods{ + NoUnkeyedLiterals: struct{}{}, + Flags: protoiface.SupportMarshalDeterministic | protoiface.SupportUnmarshalDiscardUnknown, + Size: size, + Marshal: marshal, + Unmarshal: unmarshal, + Merge: nil, + CheckInitialized: nil, + } +} + +var _ protoreflect.List = (*_QueryAllPendingReadRequestsResponse_1_list)(nil) + +type _QueryAllPendingReadRequestsResponse_1_list struct { + list *[]*UniversalRead +} + +func (x *_QueryAllPendingReadRequestsResponse_1_list) Len() int { + if x.list == nil { + return 0 + } + return len(*x.list) +} + +func (x *_QueryAllPendingReadRequestsResponse_1_list) Get(i int) protoreflect.Value { + return protoreflect.ValueOfMessage((*x.list)[i].ProtoReflect()) +} + +func (x *_QueryAllPendingReadRequestsResponse_1_list) Set(i int, value protoreflect.Value) { + valueUnwrapped := value.Message() + concreteValue := valueUnwrapped.Interface().(*UniversalRead) + (*x.list)[i] = concreteValue +} + +func (x *_QueryAllPendingReadRequestsResponse_1_list) Append(value protoreflect.Value) { + valueUnwrapped := value.Message() + concreteValue := valueUnwrapped.Interface().(*UniversalRead) + *x.list = append(*x.list, concreteValue) +} + +func (x *_QueryAllPendingReadRequestsResponse_1_list) AppendMutable() protoreflect.Value { + v := new(UniversalRead) + *x.list = append(*x.list, v) + return protoreflect.ValueOfMessage(v.ProtoReflect()) +} + +func (x *_QueryAllPendingReadRequestsResponse_1_list) Truncate(n int) { + for i := n; i < len(*x.list); i++ { + (*x.list)[i] = nil + } + *x.list = (*x.list)[:n] +} + +func (x *_QueryAllPendingReadRequestsResponse_1_list) NewElement() protoreflect.Value { + v := new(UniversalRead) + return protoreflect.ValueOfMessage(v.ProtoReflect()) +} + +func (x *_QueryAllPendingReadRequestsResponse_1_list) IsValid() bool { + return x.list != nil +} + +var ( + md_QueryAllPendingReadRequestsResponse protoreflect.MessageDescriptor + fd_QueryAllPendingReadRequestsResponse_reads protoreflect.FieldDescriptor + fd_QueryAllPendingReadRequestsResponse_pagination protoreflect.FieldDescriptor +) + +func init() { + file_ucallback_v1_query_proto_init() + md_QueryAllPendingReadRequestsResponse = File_ucallback_v1_query_proto.Messages().ByName("QueryAllPendingReadRequestsResponse") + fd_QueryAllPendingReadRequestsResponse_reads = md_QueryAllPendingReadRequestsResponse.Fields().ByName("reads") + fd_QueryAllPendingReadRequestsResponse_pagination = md_QueryAllPendingReadRequestsResponse.Fields().ByName("pagination") +} + +var _ protoreflect.Message = (*fastReflection_QueryAllPendingReadRequestsResponse)(nil) + +type fastReflection_QueryAllPendingReadRequestsResponse QueryAllPendingReadRequestsResponse + +func (x *QueryAllPendingReadRequestsResponse) ProtoReflect() protoreflect.Message { + return (*fastReflection_QueryAllPendingReadRequestsResponse)(x) +} + +func (x *QueryAllPendingReadRequestsResponse) slowProtoReflect() protoreflect.Message { + mi := &file_ucallback_v1_query_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +var _fastReflection_QueryAllPendingReadRequestsResponse_messageType fastReflection_QueryAllPendingReadRequestsResponse_messageType +var _ protoreflect.MessageType = fastReflection_QueryAllPendingReadRequestsResponse_messageType{} + +type fastReflection_QueryAllPendingReadRequestsResponse_messageType struct{} + +func (x fastReflection_QueryAllPendingReadRequestsResponse_messageType) Zero() protoreflect.Message { + return (*fastReflection_QueryAllPendingReadRequestsResponse)(nil) +} +func (x fastReflection_QueryAllPendingReadRequestsResponse_messageType) New() protoreflect.Message { + return new(fastReflection_QueryAllPendingReadRequestsResponse) +} +func (x fastReflection_QueryAllPendingReadRequestsResponse_messageType) Descriptor() protoreflect.MessageDescriptor { + return md_QueryAllPendingReadRequestsResponse +} + +// Descriptor returns message descriptor, which contains only the protobuf +// type information for the message. +func (x *fastReflection_QueryAllPendingReadRequestsResponse) Descriptor() protoreflect.MessageDescriptor { + return md_QueryAllPendingReadRequestsResponse +} + +// Type returns the message type, which encapsulates both Go and protobuf +// type information. If the Go type information is not needed, +// it is recommended that the message descriptor be used instead. +func (x *fastReflection_QueryAllPendingReadRequestsResponse) Type() protoreflect.MessageType { + return _fastReflection_QueryAllPendingReadRequestsResponse_messageType +} + +// New returns a newly allocated and mutable empty message. +func (x *fastReflection_QueryAllPendingReadRequestsResponse) New() protoreflect.Message { + return new(fastReflection_QueryAllPendingReadRequestsResponse) +} + +// Interface unwraps the message reflection interface and +// returns the underlying ProtoMessage interface. +func (x *fastReflection_QueryAllPendingReadRequestsResponse) Interface() protoreflect.ProtoMessage { + return (*QueryAllPendingReadRequestsResponse)(x) +} + +// Range iterates over every populated field in an undefined order, +// calling f for each field descriptor and value encountered. +// Range returns immediately if f returns false. +// While iterating, mutating operations may only be performed +// on the current field descriptor. +func (x *fastReflection_QueryAllPendingReadRequestsResponse) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { + if len(x.Reads) != 0 { + value := protoreflect.ValueOfList(&_QueryAllPendingReadRequestsResponse_1_list{list: &x.Reads}) + if !f(fd_QueryAllPendingReadRequestsResponse_reads, value) { + return + } + } + if x.Pagination != nil { + value := protoreflect.ValueOfMessage(x.Pagination.ProtoReflect()) + if !f(fd_QueryAllPendingReadRequestsResponse_pagination, value) { + return + } + } +} + +// Has reports whether a field is populated. +// +// Some fields have the property of nullability where it is possible to +// distinguish between the default value of a field and whether the field +// was explicitly populated with the default value. Singular message fields, +// member fields of a oneof, and proto2 scalar fields are nullable. Such +// fields are populated only if explicitly set. +// +// In other cases (aside from the nullable cases above), +// a proto3 scalar field is populated if it contains a non-zero value, and +// a repeated field is populated if it is non-empty. +func (x *fastReflection_QueryAllPendingReadRequestsResponse) Has(fd protoreflect.FieldDescriptor) bool { + switch fd.FullName() { + case "ucallback.v1.QueryAllPendingReadRequestsResponse.reads": + return len(x.Reads) != 0 + case "ucallback.v1.QueryAllPendingReadRequestsResponse.pagination": + return x.Pagination != nil + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.QueryAllPendingReadRequestsResponse")) + } + panic(fmt.Errorf("message ucallback.v1.QueryAllPendingReadRequestsResponse does not contain field %s", fd.FullName())) + } +} + +// Clear clears the field such that a subsequent Has call reports false. +// +// Clearing an extension field clears both the extension type and value +// associated with the given field number. +// +// Clear is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_QueryAllPendingReadRequestsResponse) Clear(fd protoreflect.FieldDescriptor) { + switch fd.FullName() { + case "ucallback.v1.QueryAllPendingReadRequestsResponse.reads": + x.Reads = nil + case "ucallback.v1.QueryAllPendingReadRequestsResponse.pagination": + x.Pagination = nil + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.QueryAllPendingReadRequestsResponse")) + } + panic(fmt.Errorf("message ucallback.v1.QueryAllPendingReadRequestsResponse does not contain field %s", fd.FullName())) + } +} + +// Get retrieves the value for a field. +// +// For unpopulated scalars, it returns the default value, where +// the default value of a bytes scalar is guaranteed to be a copy. +// For unpopulated composite types, it returns an empty, read-only view +// of the value; to obtain a mutable reference, use Mutable. +func (x *fastReflection_QueryAllPendingReadRequestsResponse) Get(descriptor protoreflect.FieldDescriptor) protoreflect.Value { + switch descriptor.FullName() { + case "ucallback.v1.QueryAllPendingReadRequestsResponse.reads": + if len(x.Reads) == 0 { + return protoreflect.ValueOfList(&_QueryAllPendingReadRequestsResponse_1_list{}) + } + listValue := &_QueryAllPendingReadRequestsResponse_1_list{list: &x.Reads} + return protoreflect.ValueOfList(listValue) + case "ucallback.v1.QueryAllPendingReadRequestsResponse.pagination": + value := x.Pagination + return protoreflect.ValueOfMessage(value.ProtoReflect()) + default: + if descriptor.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.QueryAllPendingReadRequestsResponse")) + } + panic(fmt.Errorf("message ucallback.v1.QueryAllPendingReadRequestsResponse does not contain field %s", descriptor.FullName())) + } +} + +// Set stores the value for a field. +// +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType. +// When setting a composite type, it is unspecified whether the stored value +// aliases the source's memory in any way. If the composite value is an +// empty, read-only value, then it panics. +// +// Set is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_QueryAllPendingReadRequestsResponse) Set(fd protoreflect.FieldDescriptor, value protoreflect.Value) { + switch fd.FullName() { + case "ucallback.v1.QueryAllPendingReadRequestsResponse.reads": + lv := value.List() + clv := lv.(*_QueryAllPendingReadRequestsResponse_1_list) + x.Reads = *clv.list + case "ucallback.v1.QueryAllPendingReadRequestsResponse.pagination": + x.Pagination = value.Message().Interface().(*v1beta1.PageResponse) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.QueryAllPendingReadRequestsResponse")) + } + panic(fmt.Errorf("message ucallback.v1.QueryAllPendingReadRequestsResponse does not contain field %s", fd.FullName())) + } +} + +// Mutable returns a mutable reference to a composite type. +// +// If the field is unpopulated, it may allocate a composite value. +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType +// if not already stored. +// It panics if the field does not contain a composite type. +// +// Mutable is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_QueryAllPendingReadRequestsResponse) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "ucallback.v1.QueryAllPendingReadRequestsResponse.reads": + if x.Reads == nil { + x.Reads = []*UniversalRead{} + } + value := &_QueryAllPendingReadRequestsResponse_1_list{list: &x.Reads} + return protoreflect.ValueOfList(value) + case "ucallback.v1.QueryAllPendingReadRequestsResponse.pagination": + if x.Pagination == nil { + x.Pagination = new(v1beta1.PageResponse) + } + return protoreflect.ValueOfMessage(x.Pagination.ProtoReflect()) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.QueryAllPendingReadRequestsResponse")) + } + panic(fmt.Errorf("message ucallback.v1.QueryAllPendingReadRequestsResponse does not contain field %s", fd.FullName())) + } +} + +// NewField returns a new value that is assignable to the field +// for the given descriptor. For scalars, this returns the default value. +// For lists, maps, and messages, this returns a new, empty, mutable value. +func (x *fastReflection_QueryAllPendingReadRequestsResponse) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "ucallback.v1.QueryAllPendingReadRequestsResponse.reads": + list := []*UniversalRead{} + return protoreflect.ValueOfList(&_QueryAllPendingReadRequestsResponse_1_list{list: &list}) + case "ucallback.v1.QueryAllPendingReadRequestsResponse.pagination": + m := new(v1beta1.PageResponse) + return protoreflect.ValueOfMessage(m.ProtoReflect()) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.QueryAllPendingReadRequestsResponse")) + } + panic(fmt.Errorf("message ucallback.v1.QueryAllPendingReadRequestsResponse does not contain field %s", fd.FullName())) + } +} + +// WhichOneof reports which field within the oneof is populated, +// returning nil if none are populated. +// It panics if the oneof descriptor does not belong to this message. +func (x *fastReflection_QueryAllPendingReadRequestsResponse) WhichOneof(d protoreflect.OneofDescriptor) protoreflect.FieldDescriptor { + switch d.FullName() { + default: + panic(fmt.Errorf("%s is not a oneof field in ucallback.v1.QueryAllPendingReadRequestsResponse", d.FullName())) + } + panic("unreachable") +} + +// GetUnknown retrieves the entire list of unknown fields. +// The caller may only mutate the contents of the RawFields +// if the mutated bytes are stored back into the message with SetUnknown. +func (x *fastReflection_QueryAllPendingReadRequestsResponse) GetUnknown() protoreflect.RawFields { + return x.unknownFields +} + +// SetUnknown stores an entire list of unknown fields. +// The raw fields must be syntactically valid according to the wire format. +// An implementation may panic if this is not the case. +// Once stored, the caller must not mutate the content of the RawFields. +// An empty RawFields may be passed to clear the fields. +// +// SetUnknown is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_QueryAllPendingReadRequestsResponse) SetUnknown(fields protoreflect.RawFields) { + x.unknownFields = fields +} + +// IsValid reports whether the message is valid. +// +// An invalid message is an empty, read-only value. +// +// An invalid message often corresponds to a nil pointer of the concrete +// message type, but the details are implementation dependent. +// Validity is not part of the protobuf data model, and may not +// be preserved in marshaling or other operations. +func (x *fastReflection_QueryAllPendingReadRequestsResponse) IsValid() bool { + return x != nil +} + +// ProtoMethods returns optional fastReflectionFeature-path implementations of various operations. +// This method may return nil. +// +// The returned methods type is identical to +// "google.golang.org/protobuf/runtime/protoiface".Methods. +// Consult the protoiface package documentation for details. +func (x *fastReflection_QueryAllPendingReadRequestsResponse) ProtoMethods() *protoiface.Methods { + size := func(input protoiface.SizeInput) protoiface.SizeOutput { + x := input.Message.Interface().(*QueryAllPendingReadRequestsResponse) + if x == nil { + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: 0, + } + } + options := runtime.SizeInputToOptions(input) + _ = options + var n int + var l int + _ = l + if len(x.Reads) > 0 { + for _, e := range x.Reads { + l = options.Size(e) + n += 1 + l + runtime.Sov(uint64(l)) + } + } + if x.Pagination != nil { + l = options.Size(x.Pagination) + n += 1 + l + runtime.Sov(uint64(l)) + } + if x.unknownFields != nil { + n += len(x.unknownFields) + } + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: n, + } + } + + marshal := func(input protoiface.MarshalInput) (protoiface.MarshalOutput, error) { + x := input.Message.Interface().(*QueryAllPendingReadRequestsResponse) + if x == nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + options := runtime.MarshalInputToOptions(input) + _ = options + size := options.Size(x) + dAtA := make([]byte, size) + i := len(dAtA) + _ = i + var l int + _ = l + if x.unknownFields != nil { + i -= len(x.unknownFields) + copy(dAtA[i:], x.unknownFields) + } + if x.Pagination != nil { + encoded, err := options.Marshal(x.Pagination) + if err != nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, err + } + i -= len(encoded) + copy(dAtA[i:], encoded) + i = runtime.EncodeVarint(dAtA, i, uint64(len(encoded))) + i-- + dAtA[i] = 0x12 + } + if len(x.Reads) > 0 { + for iNdEx := len(x.Reads) - 1; iNdEx >= 0; iNdEx-- { + encoded, err := options.Marshal(x.Reads[iNdEx]) + if err != nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, err + } + i -= len(encoded) + copy(dAtA[i:], encoded) + i = runtime.EncodeVarint(dAtA, i, uint64(len(encoded))) + i-- + dAtA[i] = 0xa + } + } + if input.Buf != nil { + input.Buf = append(input.Buf, dAtA...) + } else { + input.Buf = dAtA + } + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + unmarshal := func(input protoiface.UnmarshalInput) (protoiface.UnmarshalOutput, error) { + x := input.Message.Interface().(*QueryAllPendingReadRequestsResponse) + if x == nil { + return protoiface.UnmarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Flags: input.Flags, + }, nil + } + options := runtime.UnmarshalInputToOptions(input) + _ = options + dAtA := input.Buf + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: QueryAllPendingReadRequestsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: QueryAllPendingReadRequestsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Reads", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.Reads = append(x.Reads, &UniversalRead{}) + if err := options.Unmarshal(dAtA[iNdEx:postIndex], x.Reads[len(x.Reads)-1]); err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Pagination", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if x.Pagination == nil { + x.Pagination = &v1beta1.PageResponse{} + } + if err := options.Unmarshal(dAtA[iNdEx:postIndex], x.Pagination); err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := runtime.Skip(dAtA[iNdEx:]) + if err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if !options.DiscardUnknown { + x.unknownFields = append(x.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + } + iNdEx += skippy + } + } + + if iNdEx > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, nil + } + return &protoiface.Methods{ + NoUnkeyedLiterals: struct{}{}, + Flags: protoiface.SupportMarshalDeterministic | protoiface.SupportUnmarshalDiscardUnknown, + Size: size, + Marshal: marshal, + Unmarshal: unmarshal, + Merge: nil, + CheckInitialized: nil, + } +} + +var ( + md_QueryUniversalReadRequest protoreflect.MessageDescriptor + fd_QueryUniversalReadRequest_request_id protoreflect.FieldDescriptor +) + +func init() { + file_ucallback_v1_query_proto_init() + md_QueryUniversalReadRequest = File_ucallback_v1_query_proto.Messages().ByName("QueryUniversalReadRequest") + fd_QueryUniversalReadRequest_request_id = md_QueryUniversalReadRequest.Fields().ByName("request_id") +} + +var _ protoreflect.Message = (*fastReflection_QueryUniversalReadRequest)(nil) + +type fastReflection_QueryUniversalReadRequest QueryUniversalReadRequest + +func (x *QueryUniversalReadRequest) ProtoReflect() protoreflect.Message { + return (*fastReflection_QueryUniversalReadRequest)(x) +} + +func (x *QueryUniversalReadRequest) slowProtoReflect() protoreflect.Message { + mi := &file_ucallback_v1_query_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +var _fastReflection_QueryUniversalReadRequest_messageType fastReflection_QueryUniversalReadRequest_messageType +var _ protoreflect.MessageType = fastReflection_QueryUniversalReadRequest_messageType{} + +type fastReflection_QueryUniversalReadRequest_messageType struct{} + +func (x fastReflection_QueryUniversalReadRequest_messageType) Zero() protoreflect.Message { + return (*fastReflection_QueryUniversalReadRequest)(nil) +} +func (x fastReflection_QueryUniversalReadRequest_messageType) New() protoreflect.Message { + return new(fastReflection_QueryUniversalReadRequest) +} +func (x fastReflection_QueryUniversalReadRequest_messageType) Descriptor() protoreflect.MessageDescriptor { + return md_QueryUniversalReadRequest +} + +// Descriptor returns message descriptor, which contains only the protobuf +// type information for the message. +func (x *fastReflection_QueryUniversalReadRequest) Descriptor() protoreflect.MessageDescriptor { + return md_QueryUniversalReadRequest +} + +// Type returns the message type, which encapsulates both Go and protobuf +// type information. If the Go type information is not needed, +// it is recommended that the message descriptor be used instead. +func (x *fastReflection_QueryUniversalReadRequest) Type() protoreflect.MessageType { + return _fastReflection_QueryUniversalReadRequest_messageType +} + +// New returns a newly allocated and mutable empty message. +func (x *fastReflection_QueryUniversalReadRequest) New() protoreflect.Message { + return new(fastReflection_QueryUniversalReadRequest) +} + +// Interface unwraps the message reflection interface and +// returns the underlying ProtoMessage interface. +func (x *fastReflection_QueryUniversalReadRequest) Interface() protoreflect.ProtoMessage { + return (*QueryUniversalReadRequest)(x) +} + +// Range iterates over every populated field in an undefined order, +// calling f for each field descriptor and value encountered. +// Range returns immediately if f returns false. +// While iterating, mutating operations may only be performed +// on the current field descriptor. +func (x *fastReflection_QueryUniversalReadRequest) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { + if x.RequestId != "" { + value := protoreflect.ValueOfString(x.RequestId) + if !f(fd_QueryUniversalReadRequest_request_id, value) { + return + } + } +} + +// Has reports whether a field is populated. +// +// Some fields have the property of nullability where it is possible to +// distinguish between the default value of a field and whether the field +// was explicitly populated with the default value. Singular message fields, +// member fields of a oneof, and proto2 scalar fields are nullable. Such +// fields are populated only if explicitly set. +// +// In other cases (aside from the nullable cases above), +// a proto3 scalar field is populated if it contains a non-zero value, and +// a repeated field is populated if it is non-empty. +func (x *fastReflection_QueryUniversalReadRequest) Has(fd protoreflect.FieldDescriptor) bool { + switch fd.FullName() { + case "ucallback.v1.QueryUniversalReadRequest.request_id": + return x.RequestId != "" + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.QueryUniversalReadRequest")) + } + panic(fmt.Errorf("message ucallback.v1.QueryUniversalReadRequest does not contain field %s", fd.FullName())) + } +} + +// Clear clears the field such that a subsequent Has call reports false. +// +// Clearing an extension field clears both the extension type and value +// associated with the given field number. +// +// Clear is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_QueryUniversalReadRequest) Clear(fd protoreflect.FieldDescriptor) { + switch fd.FullName() { + case "ucallback.v1.QueryUniversalReadRequest.request_id": + x.RequestId = "" + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.QueryUniversalReadRequest")) + } + panic(fmt.Errorf("message ucallback.v1.QueryUniversalReadRequest does not contain field %s", fd.FullName())) + } +} + +// Get retrieves the value for a field. +// +// For unpopulated scalars, it returns the default value, where +// the default value of a bytes scalar is guaranteed to be a copy. +// For unpopulated composite types, it returns an empty, read-only view +// of the value; to obtain a mutable reference, use Mutable. +func (x *fastReflection_QueryUniversalReadRequest) Get(descriptor protoreflect.FieldDescriptor) protoreflect.Value { + switch descriptor.FullName() { + case "ucallback.v1.QueryUniversalReadRequest.request_id": + value := x.RequestId + return protoreflect.ValueOfString(value) + default: + if descriptor.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.QueryUniversalReadRequest")) + } + panic(fmt.Errorf("message ucallback.v1.QueryUniversalReadRequest does not contain field %s", descriptor.FullName())) + } +} + +// Set stores the value for a field. +// +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType. +// When setting a composite type, it is unspecified whether the stored value +// aliases the source's memory in any way. If the composite value is an +// empty, read-only value, then it panics. +// +// Set is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_QueryUniversalReadRequest) Set(fd protoreflect.FieldDescriptor, value protoreflect.Value) { + switch fd.FullName() { + case "ucallback.v1.QueryUniversalReadRequest.request_id": + x.RequestId = value.Interface().(string) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.QueryUniversalReadRequest")) + } + panic(fmt.Errorf("message ucallback.v1.QueryUniversalReadRequest does not contain field %s", fd.FullName())) + } +} + +// Mutable returns a mutable reference to a composite type. +// +// If the field is unpopulated, it may allocate a composite value. +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType +// if not already stored. +// It panics if the field does not contain a composite type. +// +// Mutable is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_QueryUniversalReadRequest) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "ucallback.v1.QueryUniversalReadRequest.request_id": + panic(fmt.Errorf("field request_id of message ucallback.v1.QueryUniversalReadRequest is not mutable")) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.QueryUniversalReadRequest")) + } + panic(fmt.Errorf("message ucallback.v1.QueryUniversalReadRequest does not contain field %s", fd.FullName())) + } +} + +// NewField returns a new value that is assignable to the field +// for the given descriptor. For scalars, this returns the default value. +// For lists, maps, and messages, this returns a new, empty, mutable value. +func (x *fastReflection_QueryUniversalReadRequest) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "ucallback.v1.QueryUniversalReadRequest.request_id": + return protoreflect.ValueOfString("") + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.QueryUniversalReadRequest")) + } + panic(fmt.Errorf("message ucallback.v1.QueryUniversalReadRequest does not contain field %s", fd.FullName())) + } +} + +// WhichOneof reports which field within the oneof is populated, +// returning nil if none are populated. +// It panics if the oneof descriptor does not belong to this message. +func (x *fastReflection_QueryUniversalReadRequest) WhichOneof(d protoreflect.OneofDescriptor) protoreflect.FieldDescriptor { + switch d.FullName() { + default: + panic(fmt.Errorf("%s is not a oneof field in ucallback.v1.QueryUniversalReadRequest", d.FullName())) + } + panic("unreachable") +} + +// GetUnknown retrieves the entire list of unknown fields. +// The caller may only mutate the contents of the RawFields +// if the mutated bytes are stored back into the message with SetUnknown. +func (x *fastReflection_QueryUniversalReadRequest) GetUnknown() protoreflect.RawFields { + return x.unknownFields +} + +// SetUnknown stores an entire list of unknown fields. +// The raw fields must be syntactically valid according to the wire format. +// An implementation may panic if this is not the case. +// Once stored, the caller must not mutate the content of the RawFields. +// An empty RawFields may be passed to clear the fields. +// +// SetUnknown is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_QueryUniversalReadRequest) SetUnknown(fields protoreflect.RawFields) { + x.unknownFields = fields +} + +// IsValid reports whether the message is valid. +// +// An invalid message is an empty, read-only value. +// +// An invalid message often corresponds to a nil pointer of the concrete +// message type, but the details are implementation dependent. +// Validity is not part of the protobuf data model, and may not +// be preserved in marshaling or other operations. +func (x *fastReflection_QueryUniversalReadRequest) IsValid() bool { + return x != nil +} + +// ProtoMethods returns optional fastReflectionFeature-path implementations of various operations. +// This method may return nil. +// +// The returned methods type is identical to +// "google.golang.org/protobuf/runtime/protoiface".Methods. +// Consult the protoiface package documentation for details. +func (x *fastReflection_QueryUniversalReadRequest) ProtoMethods() *protoiface.Methods { + size := func(input protoiface.SizeInput) protoiface.SizeOutput { + x := input.Message.Interface().(*QueryUniversalReadRequest) + if x == nil { + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: 0, + } + } + options := runtime.SizeInputToOptions(input) + _ = options + var n int + var l int + _ = l + l = len(x.RequestId) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } + if x.unknownFields != nil { + n += len(x.unknownFields) + } + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: n, + } + } + + marshal := func(input protoiface.MarshalInput) (protoiface.MarshalOutput, error) { + x := input.Message.Interface().(*QueryUniversalReadRequest) + if x == nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + options := runtime.MarshalInputToOptions(input) + _ = options + size := options.Size(x) + dAtA := make([]byte, size) + i := len(dAtA) + _ = i + var l int + _ = l + if x.unknownFields != nil { + i -= len(x.unknownFields) + copy(dAtA[i:], x.unknownFields) + } + if len(x.RequestId) > 0 { + i -= len(x.RequestId) + copy(dAtA[i:], x.RequestId) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.RequestId))) + i-- + dAtA[i] = 0xa + } + if input.Buf != nil { + input.Buf = append(input.Buf, dAtA...) + } else { + input.Buf = dAtA + } + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + unmarshal := func(input protoiface.UnmarshalInput) (protoiface.UnmarshalOutput, error) { + x := input.Message.Interface().(*QueryUniversalReadRequest) + if x == nil { + return protoiface.UnmarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Flags: input.Flags, + }, nil + } + options := runtime.UnmarshalInputToOptions(input) + _ = options + dAtA := input.Buf + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: QueryUniversalReadRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: QueryUniversalReadRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field RequestId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.RequestId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := runtime.Skip(dAtA[iNdEx:]) + if err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if !options.DiscardUnknown { + x.unknownFields = append(x.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + } + iNdEx += skippy + } + } + + if iNdEx > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, nil + } + return &protoiface.Methods{ + NoUnkeyedLiterals: struct{}{}, + Flags: protoiface.SupportMarshalDeterministic | protoiface.SupportUnmarshalDiscardUnknown, + Size: size, + Marshal: marshal, + Unmarshal: unmarshal, + Merge: nil, + CheckInitialized: nil, + } +} + +var ( + md_QueryUniversalReadResponse protoreflect.MessageDescriptor + fd_QueryUniversalReadResponse_read protoreflect.FieldDescriptor +) + +func init() { + file_ucallback_v1_query_proto_init() + md_QueryUniversalReadResponse = File_ucallback_v1_query_proto.Messages().ByName("QueryUniversalReadResponse") + fd_QueryUniversalReadResponse_read = md_QueryUniversalReadResponse.Fields().ByName("read") +} + +var _ protoreflect.Message = (*fastReflection_QueryUniversalReadResponse)(nil) + +type fastReflection_QueryUniversalReadResponse QueryUniversalReadResponse + +func (x *QueryUniversalReadResponse) ProtoReflect() protoreflect.Message { + return (*fastReflection_QueryUniversalReadResponse)(x) +} + +func (x *QueryUniversalReadResponse) slowProtoReflect() protoreflect.Message { + mi := &file_ucallback_v1_query_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +var _fastReflection_QueryUniversalReadResponse_messageType fastReflection_QueryUniversalReadResponse_messageType +var _ protoreflect.MessageType = fastReflection_QueryUniversalReadResponse_messageType{} + +type fastReflection_QueryUniversalReadResponse_messageType struct{} + +func (x fastReflection_QueryUniversalReadResponse_messageType) Zero() protoreflect.Message { + return (*fastReflection_QueryUniversalReadResponse)(nil) +} +func (x fastReflection_QueryUniversalReadResponse_messageType) New() protoreflect.Message { + return new(fastReflection_QueryUniversalReadResponse) +} +func (x fastReflection_QueryUniversalReadResponse_messageType) Descriptor() protoreflect.MessageDescriptor { + return md_QueryUniversalReadResponse +} + +// Descriptor returns message descriptor, which contains only the protobuf +// type information for the message. +func (x *fastReflection_QueryUniversalReadResponse) Descriptor() protoreflect.MessageDescriptor { + return md_QueryUniversalReadResponse +} + +// Type returns the message type, which encapsulates both Go and protobuf +// type information. If the Go type information is not needed, +// it is recommended that the message descriptor be used instead. +func (x *fastReflection_QueryUniversalReadResponse) Type() protoreflect.MessageType { + return _fastReflection_QueryUniversalReadResponse_messageType +} + +// New returns a newly allocated and mutable empty message. +func (x *fastReflection_QueryUniversalReadResponse) New() protoreflect.Message { + return new(fastReflection_QueryUniversalReadResponse) +} + +// Interface unwraps the message reflection interface and +// returns the underlying ProtoMessage interface. +func (x *fastReflection_QueryUniversalReadResponse) Interface() protoreflect.ProtoMessage { + return (*QueryUniversalReadResponse)(x) +} + +// Range iterates over every populated field in an undefined order, +// calling f for each field descriptor and value encountered. +// Range returns immediately if f returns false. +// While iterating, mutating operations may only be performed +// on the current field descriptor. +func (x *fastReflection_QueryUniversalReadResponse) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { + if x.Read != nil { + value := protoreflect.ValueOfMessage(x.Read.ProtoReflect()) + if !f(fd_QueryUniversalReadResponse_read, value) { + return + } + } +} + +// Has reports whether a field is populated. +// +// Some fields have the property of nullability where it is possible to +// distinguish between the default value of a field and whether the field +// was explicitly populated with the default value. Singular message fields, +// member fields of a oneof, and proto2 scalar fields are nullable. Such +// fields are populated only if explicitly set. +// +// In other cases (aside from the nullable cases above), +// a proto3 scalar field is populated if it contains a non-zero value, and +// a repeated field is populated if it is non-empty. +func (x *fastReflection_QueryUniversalReadResponse) Has(fd protoreflect.FieldDescriptor) bool { + switch fd.FullName() { + case "ucallback.v1.QueryUniversalReadResponse.read": + return x.Read != nil + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.QueryUniversalReadResponse")) + } + panic(fmt.Errorf("message ucallback.v1.QueryUniversalReadResponse does not contain field %s", fd.FullName())) + } +} + +// Clear clears the field such that a subsequent Has call reports false. +// +// Clearing an extension field clears both the extension type and value +// associated with the given field number. +// +// Clear is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_QueryUniversalReadResponse) Clear(fd protoreflect.FieldDescriptor) { + switch fd.FullName() { + case "ucallback.v1.QueryUniversalReadResponse.read": + x.Read = nil + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.QueryUniversalReadResponse")) + } + panic(fmt.Errorf("message ucallback.v1.QueryUniversalReadResponse does not contain field %s", fd.FullName())) + } +} + +// Get retrieves the value for a field. +// +// For unpopulated scalars, it returns the default value, where +// the default value of a bytes scalar is guaranteed to be a copy. +// For unpopulated composite types, it returns an empty, read-only view +// of the value; to obtain a mutable reference, use Mutable. +func (x *fastReflection_QueryUniversalReadResponse) Get(descriptor protoreflect.FieldDescriptor) protoreflect.Value { + switch descriptor.FullName() { + case "ucallback.v1.QueryUniversalReadResponse.read": + value := x.Read + return protoreflect.ValueOfMessage(value.ProtoReflect()) + default: + if descriptor.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.QueryUniversalReadResponse")) + } + panic(fmt.Errorf("message ucallback.v1.QueryUniversalReadResponse does not contain field %s", descriptor.FullName())) + } +} + +// Set stores the value for a field. +// +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType. +// When setting a composite type, it is unspecified whether the stored value +// aliases the source's memory in any way. If the composite value is an +// empty, read-only value, then it panics. +// +// Set is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_QueryUniversalReadResponse) Set(fd protoreflect.FieldDescriptor, value protoreflect.Value) { + switch fd.FullName() { + case "ucallback.v1.QueryUniversalReadResponse.read": + x.Read = value.Message().Interface().(*UniversalRead) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.QueryUniversalReadResponse")) + } + panic(fmt.Errorf("message ucallback.v1.QueryUniversalReadResponse does not contain field %s", fd.FullName())) + } +} + +// Mutable returns a mutable reference to a composite type. +// +// If the field is unpopulated, it may allocate a composite value. +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType +// if not already stored. +// It panics if the field does not contain a composite type. +// +// Mutable is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_QueryUniversalReadResponse) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "ucallback.v1.QueryUniversalReadResponse.read": + if x.Read == nil { + x.Read = new(UniversalRead) + } + return protoreflect.ValueOfMessage(x.Read.ProtoReflect()) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.QueryUniversalReadResponse")) + } + panic(fmt.Errorf("message ucallback.v1.QueryUniversalReadResponse does not contain field %s", fd.FullName())) + } +} + +// NewField returns a new value that is assignable to the field +// for the given descriptor. For scalars, this returns the default value. +// For lists, maps, and messages, this returns a new, empty, mutable value. +func (x *fastReflection_QueryUniversalReadResponse) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "ucallback.v1.QueryUniversalReadResponse.read": + m := new(UniversalRead) + return protoreflect.ValueOfMessage(m.ProtoReflect()) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.QueryUniversalReadResponse")) + } + panic(fmt.Errorf("message ucallback.v1.QueryUniversalReadResponse does not contain field %s", fd.FullName())) + } +} + +// WhichOneof reports which field within the oneof is populated, +// returning nil if none are populated. +// It panics if the oneof descriptor does not belong to this message. +func (x *fastReflection_QueryUniversalReadResponse) WhichOneof(d protoreflect.OneofDescriptor) protoreflect.FieldDescriptor { + switch d.FullName() { + default: + panic(fmt.Errorf("%s is not a oneof field in ucallback.v1.QueryUniversalReadResponse", d.FullName())) + } + panic("unreachable") +} + +// GetUnknown retrieves the entire list of unknown fields. +// The caller may only mutate the contents of the RawFields +// if the mutated bytes are stored back into the message with SetUnknown. +func (x *fastReflection_QueryUniversalReadResponse) GetUnknown() protoreflect.RawFields { + return x.unknownFields +} + +// SetUnknown stores an entire list of unknown fields. +// The raw fields must be syntactically valid according to the wire format. +// An implementation may panic if this is not the case. +// Once stored, the caller must not mutate the content of the RawFields. +// An empty RawFields may be passed to clear the fields. +// +// SetUnknown is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_QueryUniversalReadResponse) SetUnknown(fields protoreflect.RawFields) { + x.unknownFields = fields +} + +// IsValid reports whether the message is valid. +// +// An invalid message is an empty, read-only value. +// +// An invalid message often corresponds to a nil pointer of the concrete +// message type, but the details are implementation dependent. +// Validity is not part of the protobuf data model, and may not +// be preserved in marshaling or other operations. +func (x *fastReflection_QueryUniversalReadResponse) IsValid() bool { + return x != nil +} + +// ProtoMethods returns optional fastReflectionFeature-path implementations of various operations. +// This method may return nil. +// +// The returned methods type is identical to +// "google.golang.org/protobuf/runtime/protoiface".Methods. +// Consult the protoiface package documentation for details. +func (x *fastReflection_QueryUniversalReadResponse) ProtoMethods() *protoiface.Methods { + size := func(input protoiface.SizeInput) protoiface.SizeOutput { + x := input.Message.Interface().(*QueryUniversalReadResponse) + if x == nil { + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: 0, + } + } + options := runtime.SizeInputToOptions(input) + _ = options + var n int + var l int + _ = l + if x.Read != nil { + l = options.Size(x.Read) + n += 1 + l + runtime.Sov(uint64(l)) + } + if x.unknownFields != nil { + n += len(x.unknownFields) + } + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: n, + } + } + + marshal := func(input protoiface.MarshalInput) (protoiface.MarshalOutput, error) { + x := input.Message.Interface().(*QueryUniversalReadResponse) + if x == nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + options := runtime.MarshalInputToOptions(input) + _ = options + size := options.Size(x) + dAtA := make([]byte, size) + i := len(dAtA) + _ = i + var l int + _ = l + if x.unknownFields != nil { + i -= len(x.unknownFields) + copy(dAtA[i:], x.unknownFields) + } + if x.Read != nil { + encoded, err := options.Marshal(x.Read) + if err != nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, err + } + i -= len(encoded) + copy(dAtA[i:], encoded) + i = runtime.EncodeVarint(dAtA, i, uint64(len(encoded))) + i-- + dAtA[i] = 0xa + } + if input.Buf != nil { + input.Buf = append(input.Buf, dAtA...) + } else { + input.Buf = dAtA + } + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + unmarshal := func(input protoiface.UnmarshalInput) (protoiface.UnmarshalOutput, error) { + x := input.Message.Interface().(*QueryUniversalReadResponse) + if x == nil { + return protoiface.UnmarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Flags: input.Flags, + }, nil + } + options := runtime.UnmarshalInputToOptions(input) + _ = options + dAtA := input.Buf + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: QueryUniversalReadResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: QueryUniversalReadResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Read", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if x.Read == nil { + x.Read = &UniversalRead{} + } + if err := options.Unmarshal(dAtA[iNdEx:postIndex], x.Read); err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := runtime.Skip(dAtA[iNdEx:]) + if err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if !options.DiscardUnknown { + x.unknownFields = append(x.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + } + iNdEx += skippy + } + } + + if iNdEx > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, nil + } + return &protoiface.Methods{ + NoUnkeyedLiterals: struct{}{}, + Flags: protoiface.SupportMarshalDeterministic | protoiface.SupportUnmarshalDiscardUnknown, + Size: size, + Marshal: marshal, + Unmarshal: unmarshal, + Merge: nil, + CheckInitialized: nil, + } +} + +var ( + md_QueryReadsByTxRequest protoreflect.MessageDescriptor + fd_QueryReadsByTxRequest_tx_hash protoreflect.FieldDescriptor +) + +func init() { + file_ucallback_v1_query_proto_init() + md_QueryReadsByTxRequest = File_ucallback_v1_query_proto.Messages().ByName("QueryReadsByTxRequest") + fd_QueryReadsByTxRequest_tx_hash = md_QueryReadsByTxRequest.Fields().ByName("tx_hash") +} + +var _ protoreflect.Message = (*fastReflection_QueryReadsByTxRequest)(nil) + +type fastReflection_QueryReadsByTxRequest QueryReadsByTxRequest + +func (x *QueryReadsByTxRequest) ProtoReflect() protoreflect.Message { + return (*fastReflection_QueryReadsByTxRequest)(x) +} + +func (x *QueryReadsByTxRequest) slowProtoReflect() protoreflect.Message { + mi := &file_ucallback_v1_query_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +var _fastReflection_QueryReadsByTxRequest_messageType fastReflection_QueryReadsByTxRequest_messageType +var _ protoreflect.MessageType = fastReflection_QueryReadsByTxRequest_messageType{} + +type fastReflection_QueryReadsByTxRequest_messageType struct{} + +func (x fastReflection_QueryReadsByTxRequest_messageType) Zero() protoreflect.Message { + return (*fastReflection_QueryReadsByTxRequest)(nil) +} +func (x fastReflection_QueryReadsByTxRequest_messageType) New() protoreflect.Message { + return new(fastReflection_QueryReadsByTxRequest) +} +func (x fastReflection_QueryReadsByTxRequest_messageType) Descriptor() protoreflect.MessageDescriptor { + return md_QueryReadsByTxRequest +} + +// Descriptor returns message descriptor, which contains only the protobuf +// type information for the message. +func (x *fastReflection_QueryReadsByTxRequest) Descriptor() protoreflect.MessageDescriptor { + return md_QueryReadsByTxRequest +} + +// Type returns the message type, which encapsulates both Go and protobuf +// type information. If the Go type information is not needed, +// it is recommended that the message descriptor be used instead. +func (x *fastReflection_QueryReadsByTxRequest) Type() protoreflect.MessageType { + return _fastReflection_QueryReadsByTxRequest_messageType +} + +// New returns a newly allocated and mutable empty message. +func (x *fastReflection_QueryReadsByTxRequest) New() protoreflect.Message { + return new(fastReflection_QueryReadsByTxRequest) +} + +// Interface unwraps the message reflection interface and +// returns the underlying ProtoMessage interface. +func (x *fastReflection_QueryReadsByTxRequest) Interface() protoreflect.ProtoMessage { + return (*QueryReadsByTxRequest)(x) +} + +// Range iterates over every populated field in an undefined order, +// calling f for each field descriptor and value encountered. +// Range returns immediately if f returns false. +// While iterating, mutating operations may only be performed +// on the current field descriptor. +func (x *fastReflection_QueryReadsByTxRequest) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { + if x.TxHash != "" { + value := protoreflect.ValueOfString(x.TxHash) + if !f(fd_QueryReadsByTxRequest_tx_hash, value) { + return + } + } +} + +// Has reports whether a field is populated. +// +// Some fields have the property of nullability where it is possible to +// distinguish between the default value of a field and whether the field +// was explicitly populated with the default value. Singular message fields, +// member fields of a oneof, and proto2 scalar fields are nullable. Such +// fields are populated only if explicitly set. +// +// In other cases (aside from the nullable cases above), +// a proto3 scalar field is populated if it contains a non-zero value, and +// a repeated field is populated if it is non-empty. +func (x *fastReflection_QueryReadsByTxRequest) Has(fd protoreflect.FieldDescriptor) bool { + switch fd.FullName() { + case "ucallback.v1.QueryReadsByTxRequest.tx_hash": + return x.TxHash != "" + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.QueryReadsByTxRequest")) + } + panic(fmt.Errorf("message ucallback.v1.QueryReadsByTxRequest does not contain field %s", fd.FullName())) + } +} + +// Clear clears the field such that a subsequent Has call reports false. +// +// Clearing an extension field clears both the extension type and value +// associated with the given field number. +// +// Clear is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_QueryReadsByTxRequest) Clear(fd protoreflect.FieldDescriptor) { + switch fd.FullName() { + case "ucallback.v1.QueryReadsByTxRequest.tx_hash": + x.TxHash = "" + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.QueryReadsByTxRequest")) + } + panic(fmt.Errorf("message ucallback.v1.QueryReadsByTxRequest does not contain field %s", fd.FullName())) + } +} + +// Get retrieves the value for a field. +// +// For unpopulated scalars, it returns the default value, where +// the default value of a bytes scalar is guaranteed to be a copy. +// For unpopulated composite types, it returns an empty, read-only view +// of the value; to obtain a mutable reference, use Mutable. +func (x *fastReflection_QueryReadsByTxRequest) Get(descriptor protoreflect.FieldDescriptor) protoreflect.Value { + switch descriptor.FullName() { + case "ucallback.v1.QueryReadsByTxRequest.tx_hash": + value := x.TxHash + return protoreflect.ValueOfString(value) + default: + if descriptor.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.QueryReadsByTxRequest")) + } + panic(fmt.Errorf("message ucallback.v1.QueryReadsByTxRequest does not contain field %s", descriptor.FullName())) + } +} + +// Set stores the value for a field. +// +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType. +// When setting a composite type, it is unspecified whether the stored value +// aliases the source's memory in any way. If the composite value is an +// empty, read-only value, then it panics. +// +// Set is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_QueryReadsByTxRequest) Set(fd protoreflect.FieldDescriptor, value protoreflect.Value) { + switch fd.FullName() { + case "ucallback.v1.QueryReadsByTxRequest.tx_hash": + x.TxHash = value.Interface().(string) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.QueryReadsByTxRequest")) + } + panic(fmt.Errorf("message ucallback.v1.QueryReadsByTxRequest does not contain field %s", fd.FullName())) + } +} + +// Mutable returns a mutable reference to a composite type. +// +// If the field is unpopulated, it may allocate a composite value. +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType +// if not already stored. +// It panics if the field does not contain a composite type. +// +// Mutable is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_QueryReadsByTxRequest) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "ucallback.v1.QueryReadsByTxRequest.tx_hash": + panic(fmt.Errorf("field tx_hash of message ucallback.v1.QueryReadsByTxRequest is not mutable")) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.QueryReadsByTxRequest")) + } + panic(fmt.Errorf("message ucallback.v1.QueryReadsByTxRequest does not contain field %s", fd.FullName())) + } +} + +// NewField returns a new value that is assignable to the field +// for the given descriptor. For scalars, this returns the default value. +// For lists, maps, and messages, this returns a new, empty, mutable value. +func (x *fastReflection_QueryReadsByTxRequest) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "ucallback.v1.QueryReadsByTxRequest.tx_hash": + return protoreflect.ValueOfString("") + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.QueryReadsByTxRequest")) + } + panic(fmt.Errorf("message ucallback.v1.QueryReadsByTxRequest does not contain field %s", fd.FullName())) + } +} + +// WhichOneof reports which field within the oneof is populated, +// returning nil if none are populated. +// It panics if the oneof descriptor does not belong to this message. +func (x *fastReflection_QueryReadsByTxRequest) WhichOneof(d protoreflect.OneofDescriptor) protoreflect.FieldDescriptor { + switch d.FullName() { + default: + panic(fmt.Errorf("%s is not a oneof field in ucallback.v1.QueryReadsByTxRequest", d.FullName())) + } + panic("unreachable") +} + +// GetUnknown retrieves the entire list of unknown fields. +// The caller may only mutate the contents of the RawFields +// if the mutated bytes are stored back into the message with SetUnknown. +func (x *fastReflection_QueryReadsByTxRequest) GetUnknown() protoreflect.RawFields { + return x.unknownFields +} + +// SetUnknown stores an entire list of unknown fields. +// The raw fields must be syntactically valid according to the wire format. +// An implementation may panic if this is not the case. +// Once stored, the caller must not mutate the content of the RawFields. +// An empty RawFields may be passed to clear the fields. +// +// SetUnknown is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_QueryReadsByTxRequest) SetUnknown(fields protoreflect.RawFields) { + x.unknownFields = fields +} + +// IsValid reports whether the message is valid. +// +// An invalid message is an empty, read-only value. +// +// An invalid message often corresponds to a nil pointer of the concrete +// message type, but the details are implementation dependent. +// Validity is not part of the protobuf data model, and may not +// be preserved in marshaling or other operations. +func (x *fastReflection_QueryReadsByTxRequest) IsValid() bool { + return x != nil +} + +// ProtoMethods returns optional fastReflectionFeature-path implementations of various operations. +// This method may return nil. +// +// The returned methods type is identical to +// "google.golang.org/protobuf/runtime/protoiface".Methods. +// Consult the protoiface package documentation for details. +func (x *fastReflection_QueryReadsByTxRequest) ProtoMethods() *protoiface.Methods { + size := func(input protoiface.SizeInput) protoiface.SizeOutput { + x := input.Message.Interface().(*QueryReadsByTxRequest) + if x == nil { + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: 0, + } + } + options := runtime.SizeInputToOptions(input) + _ = options + var n int + var l int + _ = l + l = len(x.TxHash) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } + if x.unknownFields != nil { + n += len(x.unknownFields) + } + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: n, + } + } + + marshal := func(input protoiface.MarshalInput) (protoiface.MarshalOutput, error) { + x := input.Message.Interface().(*QueryReadsByTxRequest) + if x == nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + options := runtime.MarshalInputToOptions(input) + _ = options + size := options.Size(x) + dAtA := make([]byte, size) + i := len(dAtA) + _ = i + var l int + _ = l + if x.unknownFields != nil { + i -= len(x.unknownFields) + copy(dAtA[i:], x.unknownFields) + } + if len(x.TxHash) > 0 { + i -= len(x.TxHash) + copy(dAtA[i:], x.TxHash) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.TxHash))) + i-- + dAtA[i] = 0xa + } + if input.Buf != nil { + input.Buf = append(input.Buf, dAtA...) + } else { + input.Buf = dAtA + } + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + unmarshal := func(input protoiface.UnmarshalInput) (protoiface.UnmarshalOutput, error) { + x := input.Message.Interface().(*QueryReadsByTxRequest) + if x == nil { + return protoiface.UnmarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Flags: input.Flags, + }, nil + } + options := runtime.UnmarshalInputToOptions(input) + _ = options + dAtA := input.Buf + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: QueryReadsByTxRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: QueryReadsByTxRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field TxHash", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.TxHash = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := runtime.Skip(dAtA[iNdEx:]) + if err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if !options.DiscardUnknown { + x.unknownFields = append(x.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + } + iNdEx += skippy + } + } + + if iNdEx > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, nil + } + return &protoiface.Methods{ + NoUnkeyedLiterals: struct{}{}, + Flags: protoiface.SupportMarshalDeterministic | protoiface.SupportUnmarshalDiscardUnknown, + Size: size, + Marshal: marshal, + Unmarshal: unmarshal, + Merge: nil, + CheckInitialized: nil, + } +} + +var _ protoreflect.List = (*_QueryReadsByTxResponse_1_list)(nil) + +type _QueryReadsByTxResponse_1_list struct { + list *[]*UniversalRead +} + +func (x *_QueryReadsByTxResponse_1_list) Len() int { + if x.list == nil { + return 0 + } + return len(*x.list) +} + +func (x *_QueryReadsByTxResponse_1_list) Get(i int) protoreflect.Value { + return protoreflect.ValueOfMessage((*x.list)[i].ProtoReflect()) +} + +func (x *_QueryReadsByTxResponse_1_list) Set(i int, value protoreflect.Value) { + valueUnwrapped := value.Message() + concreteValue := valueUnwrapped.Interface().(*UniversalRead) + (*x.list)[i] = concreteValue +} + +func (x *_QueryReadsByTxResponse_1_list) Append(value protoreflect.Value) { + valueUnwrapped := value.Message() + concreteValue := valueUnwrapped.Interface().(*UniversalRead) + *x.list = append(*x.list, concreteValue) +} + +func (x *_QueryReadsByTxResponse_1_list) AppendMutable() protoreflect.Value { + v := new(UniversalRead) + *x.list = append(*x.list, v) + return protoreflect.ValueOfMessage(v.ProtoReflect()) +} + +func (x *_QueryReadsByTxResponse_1_list) Truncate(n int) { + for i := n; i < len(*x.list); i++ { + (*x.list)[i] = nil + } + *x.list = (*x.list)[:n] +} + +func (x *_QueryReadsByTxResponse_1_list) NewElement() protoreflect.Value { + v := new(UniversalRead) + return protoreflect.ValueOfMessage(v.ProtoReflect()) +} + +func (x *_QueryReadsByTxResponse_1_list) IsValid() bool { + return x.list != nil +} + +var ( + md_QueryReadsByTxResponse protoreflect.MessageDescriptor + fd_QueryReadsByTxResponse_reads protoreflect.FieldDescriptor +) + +func init() { + file_ucallback_v1_query_proto_init() + md_QueryReadsByTxResponse = File_ucallback_v1_query_proto.Messages().ByName("QueryReadsByTxResponse") + fd_QueryReadsByTxResponse_reads = md_QueryReadsByTxResponse.Fields().ByName("reads") +} + +var _ protoreflect.Message = (*fastReflection_QueryReadsByTxResponse)(nil) + +type fastReflection_QueryReadsByTxResponse QueryReadsByTxResponse + +func (x *QueryReadsByTxResponse) ProtoReflect() protoreflect.Message { + return (*fastReflection_QueryReadsByTxResponse)(x) +} + +func (x *QueryReadsByTxResponse) slowProtoReflect() protoreflect.Message { + mi := &file_ucallback_v1_query_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +var _fastReflection_QueryReadsByTxResponse_messageType fastReflection_QueryReadsByTxResponse_messageType +var _ protoreflect.MessageType = fastReflection_QueryReadsByTxResponse_messageType{} + +type fastReflection_QueryReadsByTxResponse_messageType struct{} + +func (x fastReflection_QueryReadsByTxResponse_messageType) Zero() protoreflect.Message { + return (*fastReflection_QueryReadsByTxResponse)(nil) +} +func (x fastReflection_QueryReadsByTxResponse_messageType) New() protoreflect.Message { + return new(fastReflection_QueryReadsByTxResponse) +} +func (x fastReflection_QueryReadsByTxResponse_messageType) Descriptor() protoreflect.MessageDescriptor { + return md_QueryReadsByTxResponse +} + +// Descriptor returns message descriptor, which contains only the protobuf +// type information for the message. +func (x *fastReflection_QueryReadsByTxResponse) Descriptor() protoreflect.MessageDescriptor { + return md_QueryReadsByTxResponse +} + +// Type returns the message type, which encapsulates both Go and protobuf +// type information. If the Go type information is not needed, +// it is recommended that the message descriptor be used instead. +func (x *fastReflection_QueryReadsByTxResponse) Type() protoreflect.MessageType { + return _fastReflection_QueryReadsByTxResponse_messageType +} + +// New returns a newly allocated and mutable empty message. +func (x *fastReflection_QueryReadsByTxResponse) New() protoreflect.Message { + return new(fastReflection_QueryReadsByTxResponse) +} + +// Interface unwraps the message reflection interface and +// returns the underlying ProtoMessage interface. +func (x *fastReflection_QueryReadsByTxResponse) Interface() protoreflect.ProtoMessage { + return (*QueryReadsByTxResponse)(x) +} + +// Range iterates over every populated field in an undefined order, +// calling f for each field descriptor and value encountered. +// Range returns immediately if f returns false. +// While iterating, mutating operations may only be performed +// on the current field descriptor. +func (x *fastReflection_QueryReadsByTxResponse) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { + if len(x.Reads) != 0 { + value := protoreflect.ValueOfList(&_QueryReadsByTxResponse_1_list{list: &x.Reads}) + if !f(fd_QueryReadsByTxResponse_reads, value) { + return + } + } +} + +// Has reports whether a field is populated. +// +// Some fields have the property of nullability where it is possible to +// distinguish between the default value of a field and whether the field +// was explicitly populated with the default value. Singular message fields, +// member fields of a oneof, and proto2 scalar fields are nullable. Such +// fields are populated only if explicitly set. +// +// In other cases (aside from the nullable cases above), +// a proto3 scalar field is populated if it contains a non-zero value, and +// a repeated field is populated if it is non-empty. +func (x *fastReflection_QueryReadsByTxResponse) Has(fd protoreflect.FieldDescriptor) bool { + switch fd.FullName() { + case "ucallback.v1.QueryReadsByTxResponse.reads": + return len(x.Reads) != 0 + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.QueryReadsByTxResponse")) + } + panic(fmt.Errorf("message ucallback.v1.QueryReadsByTxResponse does not contain field %s", fd.FullName())) + } +} + +// Clear clears the field such that a subsequent Has call reports false. +// +// Clearing an extension field clears both the extension type and value +// associated with the given field number. +// +// Clear is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_QueryReadsByTxResponse) Clear(fd protoreflect.FieldDescriptor) { + switch fd.FullName() { + case "ucallback.v1.QueryReadsByTxResponse.reads": + x.Reads = nil + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.QueryReadsByTxResponse")) + } + panic(fmt.Errorf("message ucallback.v1.QueryReadsByTxResponse does not contain field %s", fd.FullName())) + } +} + +// Get retrieves the value for a field. +// +// For unpopulated scalars, it returns the default value, where +// the default value of a bytes scalar is guaranteed to be a copy. +// For unpopulated composite types, it returns an empty, read-only view +// of the value; to obtain a mutable reference, use Mutable. +func (x *fastReflection_QueryReadsByTxResponse) Get(descriptor protoreflect.FieldDescriptor) protoreflect.Value { + switch descriptor.FullName() { + case "ucallback.v1.QueryReadsByTxResponse.reads": + if len(x.Reads) == 0 { + return protoreflect.ValueOfList(&_QueryReadsByTxResponse_1_list{}) + } + listValue := &_QueryReadsByTxResponse_1_list{list: &x.Reads} + return protoreflect.ValueOfList(listValue) + default: + if descriptor.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.QueryReadsByTxResponse")) + } + panic(fmt.Errorf("message ucallback.v1.QueryReadsByTxResponse does not contain field %s", descriptor.FullName())) + } +} + +// Set stores the value for a field. +// +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType. +// When setting a composite type, it is unspecified whether the stored value +// aliases the source's memory in any way. If the composite value is an +// empty, read-only value, then it panics. +// +// Set is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_QueryReadsByTxResponse) Set(fd protoreflect.FieldDescriptor, value protoreflect.Value) { + switch fd.FullName() { + case "ucallback.v1.QueryReadsByTxResponse.reads": + lv := value.List() + clv := lv.(*_QueryReadsByTxResponse_1_list) + x.Reads = *clv.list + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.QueryReadsByTxResponse")) + } + panic(fmt.Errorf("message ucallback.v1.QueryReadsByTxResponse does not contain field %s", fd.FullName())) + } +} + +// Mutable returns a mutable reference to a composite type. +// +// If the field is unpopulated, it may allocate a composite value. +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType +// if not already stored. +// It panics if the field does not contain a composite type. +// +// Mutable is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_QueryReadsByTxResponse) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "ucallback.v1.QueryReadsByTxResponse.reads": + if x.Reads == nil { + x.Reads = []*UniversalRead{} + } + value := &_QueryReadsByTxResponse_1_list{list: &x.Reads} + return protoreflect.ValueOfList(value) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.QueryReadsByTxResponse")) + } + panic(fmt.Errorf("message ucallback.v1.QueryReadsByTxResponse does not contain field %s", fd.FullName())) + } +} + +// NewField returns a new value that is assignable to the field +// for the given descriptor. For scalars, this returns the default value. +// For lists, maps, and messages, this returns a new, empty, mutable value. +func (x *fastReflection_QueryReadsByTxResponse) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "ucallback.v1.QueryReadsByTxResponse.reads": + list := []*UniversalRead{} + return protoreflect.ValueOfList(&_QueryReadsByTxResponse_1_list{list: &list}) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.QueryReadsByTxResponse")) + } + panic(fmt.Errorf("message ucallback.v1.QueryReadsByTxResponse does not contain field %s", fd.FullName())) + } +} + +// WhichOneof reports which field within the oneof is populated, +// returning nil if none are populated. +// It panics if the oneof descriptor does not belong to this message. +func (x *fastReflection_QueryReadsByTxResponse) WhichOneof(d protoreflect.OneofDescriptor) protoreflect.FieldDescriptor { + switch d.FullName() { + default: + panic(fmt.Errorf("%s is not a oneof field in ucallback.v1.QueryReadsByTxResponse", d.FullName())) + } + panic("unreachable") +} + +// GetUnknown retrieves the entire list of unknown fields. +// The caller may only mutate the contents of the RawFields +// if the mutated bytes are stored back into the message with SetUnknown. +func (x *fastReflection_QueryReadsByTxResponse) GetUnknown() protoreflect.RawFields { + return x.unknownFields +} + +// SetUnknown stores an entire list of unknown fields. +// The raw fields must be syntactically valid according to the wire format. +// An implementation may panic if this is not the case. +// Once stored, the caller must not mutate the content of the RawFields. +// An empty RawFields may be passed to clear the fields. +// +// SetUnknown is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_QueryReadsByTxResponse) SetUnknown(fields protoreflect.RawFields) { + x.unknownFields = fields +} + +// IsValid reports whether the message is valid. +// +// An invalid message is an empty, read-only value. +// +// An invalid message often corresponds to a nil pointer of the concrete +// message type, but the details are implementation dependent. +// Validity is not part of the protobuf data model, and may not +// be preserved in marshaling or other operations. +func (x *fastReflection_QueryReadsByTxResponse) IsValid() bool { + return x != nil +} + +// ProtoMethods returns optional fastReflectionFeature-path implementations of various operations. +// This method may return nil. +// +// The returned methods type is identical to +// "google.golang.org/protobuf/runtime/protoiface".Methods. +// Consult the protoiface package documentation for details. +func (x *fastReflection_QueryReadsByTxResponse) ProtoMethods() *protoiface.Methods { + size := func(input protoiface.SizeInput) protoiface.SizeOutput { + x := input.Message.Interface().(*QueryReadsByTxResponse) + if x == nil { + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: 0, + } + } + options := runtime.SizeInputToOptions(input) + _ = options + var n int + var l int + _ = l + if len(x.Reads) > 0 { + for _, e := range x.Reads { + l = options.Size(e) + n += 1 + l + runtime.Sov(uint64(l)) + } + } + if x.unknownFields != nil { + n += len(x.unknownFields) + } + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: n, + } + } + + marshal := func(input protoiface.MarshalInput) (protoiface.MarshalOutput, error) { + x := input.Message.Interface().(*QueryReadsByTxResponse) + if x == nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + options := runtime.MarshalInputToOptions(input) + _ = options + size := options.Size(x) + dAtA := make([]byte, size) + i := len(dAtA) + _ = i + var l int + _ = l + if x.unknownFields != nil { + i -= len(x.unknownFields) + copy(dAtA[i:], x.unknownFields) + } + if len(x.Reads) > 0 { + for iNdEx := len(x.Reads) - 1; iNdEx >= 0; iNdEx-- { + encoded, err := options.Marshal(x.Reads[iNdEx]) + if err != nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, err + } + i -= len(encoded) + copy(dAtA[i:], encoded) + i = runtime.EncodeVarint(dAtA, i, uint64(len(encoded))) + i-- + dAtA[i] = 0xa + } + } + if input.Buf != nil { + input.Buf = append(input.Buf, dAtA...) + } else { + input.Buf = dAtA + } + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + unmarshal := func(input protoiface.UnmarshalInput) (protoiface.UnmarshalOutput, error) { + x := input.Message.Interface().(*QueryReadsByTxResponse) + if x == nil { + return protoiface.UnmarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Flags: input.Flags, + }, nil + } + options := runtime.UnmarshalInputToOptions(input) + _ = options + dAtA := input.Buf + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: QueryReadsByTxResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: QueryReadsByTxResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Reads", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.Reads = append(x.Reads, &UniversalRead{}) + if err := options.Unmarshal(dAtA[iNdEx:postIndex], x.Reads[len(x.Reads)-1]); err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := runtime.Skip(dAtA[iNdEx:]) + if err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if !options.DiscardUnknown { + x.unknownFields = append(x.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + } + iNdEx += skippy + } + } + + if iNdEx > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, nil + } + return &protoiface.Methods{ + NoUnkeyedLiterals: struct{}{}, + Flags: protoiface.SupportMarshalDeterministic | protoiface.SupportUnmarshalDiscardUnknown, + Size: size, + Marshal: marshal, + Unmarshal: unmarshal, + Merge: nil, + CheckInitialized: nil, + } +} + +var ( + md_QueryAllAbortedReadRequestsRequest protoreflect.MessageDescriptor + fd_QueryAllAbortedReadRequestsRequest_pagination protoreflect.FieldDescriptor +) + +func init() { + file_ucallback_v1_query_proto_init() + md_QueryAllAbortedReadRequestsRequest = File_ucallback_v1_query_proto.Messages().ByName("QueryAllAbortedReadRequestsRequest") + fd_QueryAllAbortedReadRequestsRequest_pagination = md_QueryAllAbortedReadRequestsRequest.Fields().ByName("pagination") +} + +var _ protoreflect.Message = (*fastReflection_QueryAllAbortedReadRequestsRequest)(nil) + +type fastReflection_QueryAllAbortedReadRequestsRequest QueryAllAbortedReadRequestsRequest + +func (x *QueryAllAbortedReadRequestsRequest) ProtoReflect() protoreflect.Message { + return (*fastReflection_QueryAllAbortedReadRequestsRequest)(x) +} + +func (x *QueryAllAbortedReadRequestsRequest) slowProtoReflect() protoreflect.Message { + mi := &file_ucallback_v1_query_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +var _fastReflection_QueryAllAbortedReadRequestsRequest_messageType fastReflection_QueryAllAbortedReadRequestsRequest_messageType +var _ protoreflect.MessageType = fastReflection_QueryAllAbortedReadRequestsRequest_messageType{} + +type fastReflection_QueryAllAbortedReadRequestsRequest_messageType struct{} + +func (x fastReflection_QueryAllAbortedReadRequestsRequest_messageType) Zero() protoreflect.Message { + return (*fastReflection_QueryAllAbortedReadRequestsRequest)(nil) +} +func (x fastReflection_QueryAllAbortedReadRequestsRequest_messageType) New() protoreflect.Message { + return new(fastReflection_QueryAllAbortedReadRequestsRequest) +} +func (x fastReflection_QueryAllAbortedReadRequestsRequest_messageType) Descriptor() protoreflect.MessageDescriptor { + return md_QueryAllAbortedReadRequestsRequest +} + +// Descriptor returns message descriptor, which contains only the protobuf +// type information for the message. +func (x *fastReflection_QueryAllAbortedReadRequestsRequest) Descriptor() protoreflect.MessageDescriptor { + return md_QueryAllAbortedReadRequestsRequest +} + +// Type returns the message type, which encapsulates both Go and protobuf +// type information. If the Go type information is not needed, +// it is recommended that the message descriptor be used instead. +func (x *fastReflection_QueryAllAbortedReadRequestsRequest) Type() protoreflect.MessageType { + return _fastReflection_QueryAllAbortedReadRequestsRequest_messageType +} + +// New returns a newly allocated and mutable empty message. +func (x *fastReflection_QueryAllAbortedReadRequestsRequest) New() protoreflect.Message { + return new(fastReflection_QueryAllAbortedReadRequestsRequest) +} + +// Interface unwraps the message reflection interface and +// returns the underlying ProtoMessage interface. +func (x *fastReflection_QueryAllAbortedReadRequestsRequest) Interface() protoreflect.ProtoMessage { + return (*QueryAllAbortedReadRequestsRequest)(x) +} + +// Range iterates over every populated field in an undefined order, +// calling f for each field descriptor and value encountered. +// Range returns immediately if f returns false. +// While iterating, mutating operations may only be performed +// on the current field descriptor. +func (x *fastReflection_QueryAllAbortedReadRequestsRequest) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { + if x.Pagination != nil { + value := protoreflect.ValueOfMessage(x.Pagination.ProtoReflect()) + if !f(fd_QueryAllAbortedReadRequestsRequest_pagination, value) { + return + } + } +} + +// Has reports whether a field is populated. +// +// Some fields have the property of nullability where it is possible to +// distinguish between the default value of a field and whether the field +// was explicitly populated with the default value. Singular message fields, +// member fields of a oneof, and proto2 scalar fields are nullable. Such +// fields are populated only if explicitly set. +// +// In other cases (aside from the nullable cases above), +// a proto3 scalar field is populated if it contains a non-zero value, and +// a repeated field is populated if it is non-empty. +func (x *fastReflection_QueryAllAbortedReadRequestsRequest) Has(fd protoreflect.FieldDescriptor) bool { + switch fd.FullName() { + case "ucallback.v1.QueryAllAbortedReadRequestsRequest.pagination": + return x.Pagination != nil + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.QueryAllAbortedReadRequestsRequest")) + } + panic(fmt.Errorf("message ucallback.v1.QueryAllAbortedReadRequestsRequest does not contain field %s", fd.FullName())) + } +} + +// Clear clears the field such that a subsequent Has call reports false. +// +// Clearing an extension field clears both the extension type and value +// associated with the given field number. +// +// Clear is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_QueryAllAbortedReadRequestsRequest) Clear(fd protoreflect.FieldDescriptor) { + switch fd.FullName() { + case "ucallback.v1.QueryAllAbortedReadRequestsRequest.pagination": + x.Pagination = nil + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.QueryAllAbortedReadRequestsRequest")) + } + panic(fmt.Errorf("message ucallback.v1.QueryAllAbortedReadRequestsRequest does not contain field %s", fd.FullName())) + } +} + +// Get retrieves the value for a field. +// +// For unpopulated scalars, it returns the default value, where +// the default value of a bytes scalar is guaranteed to be a copy. +// For unpopulated composite types, it returns an empty, read-only view +// of the value; to obtain a mutable reference, use Mutable. +func (x *fastReflection_QueryAllAbortedReadRequestsRequest) Get(descriptor protoreflect.FieldDescriptor) protoreflect.Value { + switch descriptor.FullName() { + case "ucallback.v1.QueryAllAbortedReadRequestsRequest.pagination": + value := x.Pagination + return protoreflect.ValueOfMessage(value.ProtoReflect()) + default: + if descriptor.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.QueryAllAbortedReadRequestsRequest")) + } + panic(fmt.Errorf("message ucallback.v1.QueryAllAbortedReadRequestsRequest does not contain field %s", descriptor.FullName())) + } +} + +// Set stores the value for a field. +// +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType. +// When setting a composite type, it is unspecified whether the stored value +// aliases the source's memory in any way. If the composite value is an +// empty, read-only value, then it panics. +// +// Set is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_QueryAllAbortedReadRequestsRequest) Set(fd protoreflect.FieldDescriptor, value protoreflect.Value) { + switch fd.FullName() { + case "ucallback.v1.QueryAllAbortedReadRequestsRequest.pagination": + x.Pagination = value.Message().Interface().(*v1beta1.PageRequest) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.QueryAllAbortedReadRequestsRequest")) + } + panic(fmt.Errorf("message ucallback.v1.QueryAllAbortedReadRequestsRequest does not contain field %s", fd.FullName())) + } +} + +// Mutable returns a mutable reference to a composite type. +// +// If the field is unpopulated, it may allocate a composite value. +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType +// if not already stored. +// It panics if the field does not contain a composite type. +// +// Mutable is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_QueryAllAbortedReadRequestsRequest) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "ucallback.v1.QueryAllAbortedReadRequestsRequest.pagination": + if x.Pagination == nil { + x.Pagination = new(v1beta1.PageRequest) + } + return protoreflect.ValueOfMessage(x.Pagination.ProtoReflect()) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.QueryAllAbortedReadRequestsRequest")) + } + panic(fmt.Errorf("message ucallback.v1.QueryAllAbortedReadRequestsRequest does not contain field %s", fd.FullName())) + } +} + +// NewField returns a new value that is assignable to the field +// for the given descriptor. For scalars, this returns the default value. +// For lists, maps, and messages, this returns a new, empty, mutable value. +func (x *fastReflection_QueryAllAbortedReadRequestsRequest) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "ucallback.v1.QueryAllAbortedReadRequestsRequest.pagination": + m := new(v1beta1.PageRequest) + return protoreflect.ValueOfMessage(m.ProtoReflect()) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.QueryAllAbortedReadRequestsRequest")) + } + panic(fmt.Errorf("message ucallback.v1.QueryAllAbortedReadRequestsRequest does not contain field %s", fd.FullName())) + } +} + +// WhichOneof reports which field within the oneof is populated, +// returning nil if none are populated. +// It panics if the oneof descriptor does not belong to this message. +func (x *fastReflection_QueryAllAbortedReadRequestsRequest) WhichOneof(d protoreflect.OneofDescriptor) protoreflect.FieldDescriptor { + switch d.FullName() { + default: + panic(fmt.Errorf("%s is not a oneof field in ucallback.v1.QueryAllAbortedReadRequestsRequest", d.FullName())) + } + panic("unreachable") +} + +// GetUnknown retrieves the entire list of unknown fields. +// The caller may only mutate the contents of the RawFields +// if the mutated bytes are stored back into the message with SetUnknown. +func (x *fastReflection_QueryAllAbortedReadRequestsRequest) GetUnknown() protoreflect.RawFields { + return x.unknownFields +} + +// SetUnknown stores an entire list of unknown fields. +// The raw fields must be syntactically valid according to the wire format. +// An implementation may panic if this is not the case. +// Once stored, the caller must not mutate the content of the RawFields. +// An empty RawFields may be passed to clear the fields. +// +// SetUnknown is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_QueryAllAbortedReadRequestsRequest) SetUnknown(fields protoreflect.RawFields) { + x.unknownFields = fields +} + +// IsValid reports whether the message is valid. +// +// An invalid message is an empty, read-only value. +// +// An invalid message often corresponds to a nil pointer of the concrete +// message type, but the details are implementation dependent. +// Validity is not part of the protobuf data model, and may not +// be preserved in marshaling or other operations. +func (x *fastReflection_QueryAllAbortedReadRequestsRequest) IsValid() bool { + return x != nil +} + +// ProtoMethods returns optional fastReflectionFeature-path implementations of various operations. +// This method may return nil. +// +// The returned methods type is identical to +// "google.golang.org/protobuf/runtime/protoiface".Methods. +// Consult the protoiface package documentation for details. +func (x *fastReflection_QueryAllAbortedReadRequestsRequest) ProtoMethods() *protoiface.Methods { + size := func(input protoiface.SizeInput) protoiface.SizeOutput { + x := input.Message.Interface().(*QueryAllAbortedReadRequestsRequest) + if x == nil { + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: 0, + } + } + options := runtime.SizeInputToOptions(input) + _ = options + var n int + var l int + _ = l + if x.Pagination != nil { + l = options.Size(x.Pagination) + n += 1 + l + runtime.Sov(uint64(l)) + } + if x.unknownFields != nil { + n += len(x.unknownFields) + } + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: n, + } + } + + marshal := func(input protoiface.MarshalInput) (protoiface.MarshalOutput, error) { + x := input.Message.Interface().(*QueryAllAbortedReadRequestsRequest) + if x == nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + options := runtime.MarshalInputToOptions(input) + _ = options + size := options.Size(x) + dAtA := make([]byte, size) + i := len(dAtA) + _ = i + var l int + _ = l + if x.unknownFields != nil { + i -= len(x.unknownFields) + copy(dAtA[i:], x.unknownFields) + } + if x.Pagination != nil { + encoded, err := options.Marshal(x.Pagination) + if err != nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, err + } + i -= len(encoded) + copy(dAtA[i:], encoded) + i = runtime.EncodeVarint(dAtA, i, uint64(len(encoded))) + i-- + dAtA[i] = 0xa + } + if input.Buf != nil { + input.Buf = append(input.Buf, dAtA...) + } else { + input.Buf = dAtA + } + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + unmarshal := func(input protoiface.UnmarshalInput) (protoiface.UnmarshalOutput, error) { + x := input.Message.Interface().(*QueryAllAbortedReadRequestsRequest) + if x == nil { + return protoiface.UnmarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Flags: input.Flags, + }, nil + } + options := runtime.UnmarshalInputToOptions(input) + _ = options + dAtA := input.Buf + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: QueryAllAbortedReadRequestsRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: QueryAllAbortedReadRequestsRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Pagination", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if x.Pagination == nil { + x.Pagination = &v1beta1.PageRequest{} + } + if err := options.Unmarshal(dAtA[iNdEx:postIndex], x.Pagination); err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := runtime.Skip(dAtA[iNdEx:]) + if err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if !options.DiscardUnknown { + x.unknownFields = append(x.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + } + iNdEx += skippy + } + } + + if iNdEx > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, nil + } + return &protoiface.Methods{ + NoUnkeyedLiterals: struct{}{}, + Flags: protoiface.SupportMarshalDeterministic | protoiface.SupportUnmarshalDiscardUnknown, + Size: size, + Marshal: marshal, + Unmarshal: unmarshal, + Merge: nil, + CheckInitialized: nil, + } +} + +var _ protoreflect.List = (*_QueryAllAbortedReadRequestsResponse_1_list)(nil) + +type _QueryAllAbortedReadRequestsResponse_1_list struct { + list *[]*UniversalRead +} + +func (x *_QueryAllAbortedReadRequestsResponse_1_list) Len() int { + if x.list == nil { + return 0 + } + return len(*x.list) +} + +func (x *_QueryAllAbortedReadRequestsResponse_1_list) Get(i int) protoreflect.Value { + return protoreflect.ValueOfMessage((*x.list)[i].ProtoReflect()) +} + +func (x *_QueryAllAbortedReadRequestsResponse_1_list) Set(i int, value protoreflect.Value) { + valueUnwrapped := value.Message() + concreteValue := valueUnwrapped.Interface().(*UniversalRead) + (*x.list)[i] = concreteValue +} + +func (x *_QueryAllAbortedReadRequestsResponse_1_list) Append(value protoreflect.Value) { + valueUnwrapped := value.Message() + concreteValue := valueUnwrapped.Interface().(*UniversalRead) + *x.list = append(*x.list, concreteValue) +} + +func (x *_QueryAllAbortedReadRequestsResponse_1_list) AppendMutable() protoreflect.Value { + v := new(UniversalRead) + *x.list = append(*x.list, v) + return protoreflect.ValueOfMessage(v.ProtoReflect()) +} + +func (x *_QueryAllAbortedReadRequestsResponse_1_list) Truncate(n int) { + for i := n; i < len(*x.list); i++ { + (*x.list)[i] = nil + } + *x.list = (*x.list)[:n] +} + +func (x *_QueryAllAbortedReadRequestsResponse_1_list) NewElement() protoreflect.Value { + v := new(UniversalRead) + return protoreflect.ValueOfMessage(v.ProtoReflect()) +} + +func (x *_QueryAllAbortedReadRequestsResponse_1_list) IsValid() bool { + return x.list != nil +} + +var ( + md_QueryAllAbortedReadRequestsResponse protoreflect.MessageDescriptor + fd_QueryAllAbortedReadRequestsResponse_reads protoreflect.FieldDescriptor + fd_QueryAllAbortedReadRequestsResponse_pagination protoreflect.FieldDescriptor +) + +func init() { + file_ucallback_v1_query_proto_init() + md_QueryAllAbortedReadRequestsResponse = File_ucallback_v1_query_proto.Messages().ByName("QueryAllAbortedReadRequestsResponse") + fd_QueryAllAbortedReadRequestsResponse_reads = md_QueryAllAbortedReadRequestsResponse.Fields().ByName("reads") + fd_QueryAllAbortedReadRequestsResponse_pagination = md_QueryAllAbortedReadRequestsResponse.Fields().ByName("pagination") +} + +var _ protoreflect.Message = (*fastReflection_QueryAllAbortedReadRequestsResponse)(nil) + +type fastReflection_QueryAllAbortedReadRequestsResponse QueryAllAbortedReadRequestsResponse + +func (x *QueryAllAbortedReadRequestsResponse) ProtoReflect() protoreflect.Message { + return (*fastReflection_QueryAllAbortedReadRequestsResponse)(x) +} + +func (x *QueryAllAbortedReadRequestsResponse) slowProtoReflect() protoreflect.Message { + mi := &file_ucallback_v1_query_proto_msgTypes[9] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +var _fastReflection_QueryAllAbortedReadRequestsResponse_messageType fastReflection_QueryAllAbortedReadRequestsResponse_messageType +var _ protoreflect.MessageType = fastReflection_QueryAllAbortedReadRequestsResponse_messageType{} + +type fastReflection_QueryAllAbortedReadRequestsResponse_messageType struct{} + +func (x fastReflection_QueryAllAbortedReadRequestsResponse_messageType) Zero() protoreflect.Message { + return (*fastReflection_QueryAllAbortedReadRequestsResponse)(nil) +} +func (x fastReflection_QueryAllAbortedReadRequestsResponse_messageType) New() protoreflect.Message { + return new(fastReflection_QueryAllAbortedReadRequestsResponse) +} +func (x fastReflection_QueryAllAbortedReadRequestsResponse_messageType) Descriptor() protoreflect.MessageDescriptor { + return md_QueryAllAbortedReadRequestsResponse +} + +// Descriptor returns message descriptor, which contains only the protobuf +// type information for the message. +func (x *fastReflection_QueryAllAbortedReadRequestsResponse) Descriptor() protoreflect.MessageDescriptor { + return md_QueryAllAbortedReadRequestsResponse +} + +// Type returns the message type, which encapsulates both Go and protobuf +// type information. If the Go type information is not needed, +// it is recommended that the message descriptor be used instead. +func (x *fastReflection_QueryAllAbortedReadRequestsResponse) Type() protoreflect.MessageType { + return _fastReflection_QueryAllAbortedReadRequestsResponse_messageType +} + +// New returns a newly allocated and mutable empty message. +func (x *fastReflection_QueryAllAbortedReadRequestsResponse) New() protoreflect.Message { + return new(fastReflection_QueryAllAbortedReadRequestsResponse) +} + +// Interface unwraps the message reflection interface and +// returns the underlying ProtoMessage interface. +func (x *fastReflection_QueryAllAbortedReadRequestsResponse) Interface() protoreflect.ProtoMessage { + return (*QueryAllAbortedReadRequestsResponse)(x) +} + +// Range iterates over every populated field in an undefined order, +// calling f for each field descriptor and value encountered. +// Range returns immediately if f returns false. +// While iterating, mutating operations may only be performed +// on the current field descriptor. +func (x *fastReflection_QueryAllAbortedReadRequestsResponse) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { + if len(x.Reads) != 0 { + value := protoreflect.ValueOfList(&_QueryAllAbortedReadRequestsResponse_1_list{list: &x.Reads}) + if !f(fd_QueryAllAbortedReadRequestsResponse_reads, value) { + return + } + } + if x.Pagination != nil { + value := protoreflect.ValueOfMessage(x.Pagination.ProtoReflect()) + if !f(fd_QueryAllAbortedReadRequestsResponse_pagination, value) { + return + } + } +} + +// Has reports whether a field is populated. +// +// Some fields have the property of nullability where it is possible to +// distinguish between the default value of a field and whether the field +// was explicitly populated with the default value. Singular message fields, +// member fields of a oneof, and proto2 scalar fields are nullable. Such +// fields are populated only if explicitly set. +// +// In other cases (aside from the nullable cases above), +// a proto3 scalar field is populated if it contains a non-zero value, and +// a repeated field is populated if it is non-empty. +func (x *fastReflection_QueryAllAbortedReadRequestsResponse) Has(fd protoreflect.FieldDescriptor) bool { + switch fd.FullName() { + case "ucallback.v1.QueryAllAbortedReadRequestsResponse.reads": + return len(x.Reads) != 0 + case "ucallback.v1.QueryAllAbortedReadRequestsResponse.pagination": + return x.Pagination != nil + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.QueryAllAbortedReadRequestsResponse")) + } + panic(fmt.Errorf("message ucallback.v1.QueryAllAbortedReadRequestsResponse does not contain field %s", fd.FullName())) + } +} + +// Clear clears the field such that a subsequent Has call reports false. +// +// Clearing an extension field clears both the extension type and value +// associated with the given field number. +// +// Clear is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_QueryAllAbortedReadRequestsResponse) Clear(fd protoreflect.FieldDescriptor) { + switch fd.FullName() { + case "ucallback.v1.QueryAllAbortedReadRequestsResponse.reads": + x.Reads = nil + case "ucallback.v1.QueryAllAbortedReadRequestsResponse.pagination": + x.Pagination = nil + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.QueryAllAbortedReadRequestsResponse")) + } + panic(fmt.Errorf("message ucallback.v1.QueryAllAbortedReadRequestsResponse does not contain field %s", fd.FullName())) + } +} + +// Get retrieves the value for a field. +// +// For unpopulated scalars, it returns the default value, where +// the default value of a bytes scalar is guaranteed to be a copy. +// For unpopulated composite types, it returns an empty, read-only view +// of the value; to obtain a mutable reference, use Mutable. +func (x *fastReflection_QueryAllAbortedReadRequestsResponse) Get(descriptor protoreflect.FieldDescriptor) protoreflect.Value { + switch descriptor.FullName() { + case "ucallback.v1.QueryAllAbortedReadRequestsResponse.reads": + if len(x.Reads) == 0 { + return protoreflect.ValueOfList(&_QueryAllAbortedReadRequestsResponse_1_list{}) + } + listValue := &_QueryAllAbortedReadRequestsResponse_1_list{list: &x.Reads} + return protoreflect.ValueOfList(listValue) + case "ucallback.v1.QueryAllAbortedReadRequestsResponse.pagination": + value := x.Pagination + return protoreflect.ValueOfMessage(value.ProtoReflect()) + default: + if descriptor.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.QueryAllAbortedReadRequestsResponse")) + } + panic(fmt.Errorf("message ucallback.v1.QueryAllAbortedReadRequestsResponse does not contain field %s", descriptor.FullName())) + } +} + +// Set stores the value for a field. +// +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType. +// When setting a composite type, it is unspecified whether the stored value +// aliases the source's memory in any way. If the composite value is an +// empty, read-only value, then it panics. +// +// Set is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_QueryAllAbortedReadRequestsResponse) Set(fd protoreflect.FieldDescriptor, value protoreflect.Value) { + switch fd.FullName() { + case "ucallback.v1.QueryAllAbortedReadRequestsResponse.reads": + lv := value.List() + clv := lv.(*_QueryAllAbortedReadRequestsResponse_1_list) + x.Reads = *clv.list + case "ucallback.v1.QueryAllAbortedReadRequestsResponse.pagination": + x.Pagination = value.Message().Interface().(*v1beta1.PageResponse) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.QueryAllAbortedReadRequestsResponse")) + } + panic(fmt.Errorf("message ucallback.v1.QueryAllAbortedReadRequestsResponse does not contain field %s", fd.FullName())) + } +} + +// Mutable returns a mutable reference to a composite type. +// +// If the field is unpopulated, it may allocate a composite value. +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType +// if not already stored. +// It panics if the field does not contain a composite type. +// +// Mutable is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_QueryAllAbortedReadRequestsResponse) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "ucallback.v1.QueryAllAbortedReadRequestsResponse.reads": + if x.Reads == nil { + x.Reads = []*UniversalRead{} + } + value := &_QueryAllAbortedReadRequestsResponse_1_list{list: &x.Reads} + return protoreflect.ValueOfList(value) + case "ucallback.v1.QueryAllAbortedReadRequestsResponse.pagination": + if x.Pagination == nil { + x.Pagination = new(v1beta1.PageResponse) + } + return protoreflect.ValueOfMessage(x.Pagination.ProtoReflect()) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.QueryAllAbortedReadRequestsResponse")) + } + panic(fmt.Errorf("message ucallback.v1.QueryAllAbortedReadRequestsResponse does not contain field %s", fd.FullName())) + } +} + +// NewField returns a new value that is assignable to the field +// for the given descriptor. For scalars, this returns the default value. +// For lists, maps, and messages, this returns a new, empty, mutable value. +func (x *fastReflection_QueryAllAbortedReadRequestsResponse) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "ucallback.v1.QueryAllAbortedReadRequestsResponse.reads": + list := []*UniversalRead{} + return protoreflect.ValueOfList(&_QueryAllAbortedReadRequestsResponse_1_list{list: &list}) + case "ucallback.v1.QueryAllAbortedReadRequestsResponse.pagination": + m := new(v1beta1.PageResponse) + return protoreflect.ValueOfMessage(m.ProtoReflect()) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.QueryAllAbortedReadRequestsResponse")) + } + panic(fmt.Errorf("message ucallback.v1.QueryAllAbortedReadRequestsResponse does not contain field %s", fd.FullName())) + } +} + +// WhichOneof reports which field within the oneof is populated, +// returning nil if none are populated. +// It panics if the oneof descriptor does not belong to this message. +func (x *fastReflection_QueryAllAbortedReadRequestsResponse) WhichOneof(d protoreflect.OneofDescriptor) protoreflect.FieldDescriptor { + switch d.FullName() { + default: + panic(fmt.Errorf("%s is not a oneof field in ucallback.v1.QueryAllAbortedReadRequestsResponse", d.FullName())) + } + panic("unreachable") +} + +// GetUnknown retrieves the entire list of unknown fields. +// The caller may only mutate the contents of the RawFields +// if the mutated bytes are stored back into the message with SetUnknown. +func (x *fastReflection_QueryAllAbortedReadRequestsResponse) GetUnknown() protoreflect.RawFields { + return x.unknownFields +} + +// SetUnknown stores an entire list of unknown fields. +// The raw fields must be syntactically valid according to the wire format. +// An implementation may panic if this is not the case. +// Once stored, the caller must not mutate the content of the RawFields. +// An empty RawFields may be passed to clear the fields. +// +// SetUnknown is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_QueryAllAbortedReadRequestsResponse) SetUnknown(fields protoreflect.RawFields) { + x.unknownFields = fields +} + +// IsValid reports whether the message is valid. +// +// An invalid message is an empty, read-only value. +// +// An invalid message often corresponds to a nil pointer of the concrete +// message type, but the details are implementation dependent. +// Validity is not part of the protobuf data model, and may not +// be preserved in marshaling or other operations. +func (x *fastReflection_QueryAllAbortedReadRequestsResponse) IsValid() bool { + return x != nil +} + +// ProtoMethods returns optional fastReflectionFeature-path implementations of various operations. +// This method may return nil. +// +// The returned methods type is identical to +// "google.golang.org/protobuf/runtime/protoiface".Methods. +// Consult the protoiface package documentation for details. +func (x *fastReflection_QueryAllAbortedReadRequestsResponse) ProtoMethods() *protoiface.Methods { + size := func(input protoiface.SizeInput) protoiface.SizeOutput { + x := input.Message.Interface().(*QueryAllAbortedReadRequestsResponse) + if x == nil { + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: 0, + } + } + options := runtime.SizeInputToOptions(input) + _ = options + var n int + var l int + _ = l + if len(x.Reads) > 0 { + for _, e := range x.Reads { + l = options.Size(e) + n += 1 + l + runtime.Sov(uint64(l)) + } + } + if x.Pagination != nil { + l = options.Size(x.Pagination) + n += 1 + l + runtime.Sov(uint64(l)) + } + if x.unknownFields != nil { + n += len(x.unknownFields) + } + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: n, + } + } + + marshal := func(input protoiface.MarshalInput) (protoiface.MarshalOutput, error) { + x := input.Message.Interface().(*QueryAllAbortedReadRequestsResponse) + if x == nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + options := runtime.MarshalInputToOptions(input) + _ = options + size := options.Size(x) + dAtA := make([]byte, size) + i := len(dAtA) + _ = i + var l int + _ = l + if x.unknownFields != nil { + i -= len(x.unknownFields) + copy(dAtA[i:], x.unknownFields) + } + if x.Pagination != nil { + encoded, err := options.Marshal(x.Pagination) + if err != nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, err + } + i -= len(encoded) + copy(dAtA[i:], encoded) + i = runtime.EncodeVarint(dAtA, i, uint64(len(encoded))) + i-- + dAtA[i] = 0x12 + } + if len(x.Reads) > 0 { + for iNdEx := len(x.Reads) - 1; iNdEx >= 0; iNdEx-- { + encoded, err := options.Marshal(x.Reads[iNdEx]) + if err != nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, err + } + i -= len(encoded) + copy(dAtA[i:], encoded) + i = runtime.EncodeVarint(dAtA, i, uint64(len(encoded))) + i-- + dAtA[i] = 0xa + } + } + if input.Buf != nil { + input.Buf = append(input.Buf, dAtA...) + } else { + input.Buf = dAtA + } + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + unmarshal := func(input protoiface.UnmarshalInput) (protoiface.UnmarshalOutput, error) { + x := input.Message.Interface().(*QueryAllAbortedReadRequestsResponse) + if x == nil { + return protoiface.UnmarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Flags: input.Flags, + }, nil + } + options := runtime.UnmarshalInputToOptions(input) + _ = options + dAtA := input.Buf + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: QueryAllAbortedReadRequestsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: QueryAllAbortedReadRequestsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Reads", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.Reads = append(x.Reads, &UniversalRead{}) + if err := options.Unmarshal(dAtA[iNdEx:postIndex], x.Reads[len(x.Reads)-1]); err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Pagination", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if x.Pagination == nil { + x.Pagination = &v1beta1.PageResponse{} + } + if err := options.Unmarshal(dAtA[iNdEx:postIndex], x.Pagination); err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := runtime.Skip(dAtA[iNdEx:]) + if err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if !options.DiscardUnknown { + x.unknownFields = append(x.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + } + iNdEx += skippy + } + } + + if iNdEx > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, nil + } + return &protoiface.Methods{ + NoUnkeyedLiterals: struct{}{}, + Flags: protoiface.SupportMarshalDeterministic | protoiface.SupportUnmarshalDiscardUnknown, + Size: size, + Marshal: marshal, + Unmarshal: unmarshal, + Merge: nil, + CheckInitialized: nil, + } +} + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.27.0 +// protoc (unknown) +// source: ucallback/v1/query.proto + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// QueryParamsRequest is the request type for the Query/Params RPC method. +type QueryParamsRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *QueryParamsRequest) Reset() { + *x = QueryParamsRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_ucallback_v1_query_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *QueryParamsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*QueryParamsRequest) ProtoMessage() {} + +// Deprecated: Use QueryParamsRequest.ProtoReflect.Descriptor instead. +func (*QueryParamsRequest) Descriptor() ([]byte, []int) { + return file_ucallback_v1_query_proto_rawDescGZIP(), []int{0} +} + +// QueryParamsResponse is the response type for the Query/Params RPC method. +type QueryParamsResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // params defines the parameters of the module. + Params *Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params,omitempty"` +} + +func (x *QueryParamsResponse) Reset() { + *x = QueryParamsResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_ucallback_v1_query_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *QueryParamsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*QueryParamsResponse) ProtoMessage() {} + +// Deprecated: Use QueryParamsResponse.ProtoReflect.Descriptor instead. +func (*QueryParamsResponse) Descriptor() ([]byte, []int) { + return file_ucallback_v1_query_proto_rawDescGZIP(), []int{1} +} + +func (x *QueryParamsResponse) GetParams() *Params { + if x != nil { + return x.Params + } + return nil +} + +type QueryAllPendingReadRequestsRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Pagination *v1beta1.PageRequest `protobuf:"bytes,1,opt,name=pagination,proto3" json:"pagination,omitempty"` +} + +func (x *QueryAllPendingReadRequestsRequest) Reset() { + *x = QueryAllPendingReadRequestsRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_ucallback_v1_query_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *QueryAllPendingReadRequestsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*QueryAllPendingReadRequestsRequest) ProtoMessage() {} + +// Deprecated: Use QueryAllPendingReadRequestsRequest.ProtoReflect.Descriptor instead. +func (*QueryAllPendingReadRequestsRequest) Descriptor() ([]byte, []int) { + return file_ucallback_v1_query_proto_rawDescGZIP(), []int{2} +} + +func (x *QueryAllPendingReadRequestsRequest) GetPagination() *v1beta1.PageRequest { + if x != nil { + return x.Pagination + } + return nil +} + +type QueryAllPendingReadRequestsResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Reads that are unsettled AND not yet past their expiry height. Requests past + // expiry are withheld here even before the sweeper retires them, so validators + // never take on work that can no longer be fulfilled in time. + Reads []*UniversalRead `protobuf:"bytes,1,rep,name=reads,proto3" json:"reads,omitempty"` + Pagination *v1beta1.PageResponse `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination,omitempty"` +} + +func (x *QueryAllPendingReadRequestsResponse) Reset() { + *x = QueryAllPendingReadRequestsResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_ucallback_v1_query_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *QueryAllPendingReadRequestsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*QueryAllPendingReadRequestsResponse) ProtoMessage() {} + +// Deprecated: Use QueryAllPendingReadRequestsResponse.ProtoReflect.Descriptor instead. +func (*QueryAllPendingReadRequestsResponse) Descriptor() ([]byte, []int) { + return file_ucallback_v1_query_proto_rawDescGZIP(), []int{3} +} + +func (x *QueryAllPendingReadRequestsResponse) GetReads() []*UniversalRead { + if x != nil { + return x.Reads + } + return nil +} + +func (x *QueryAllPendingReadRequestsResponse) GetPagination() *v1beta1.PageResponse { + if x != nil { + return x.Pagination + } + return nil +} + +type QueryUniversalReadRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + RequestId string `protobuf:"bytes,1,opt,name=request_id,json=requestId,proto3" json:"request_id,omitempty"` +} + +func (x *QueryUniversalReadRequest) Reset() { + *x = QueryUniversalReadRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_ucallback_v1_query_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *QueryUniversalReadRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*QueryUniversalReadRequest) ProtoMessage() {} + +// Deprecated: Use QueryUniversalReadRequest.ProtoReflect.Descriptor instead. +func (*QueryUniversalReadRequest) Descriptor() ([]byte, []int) { + return file_ucallback_v1_query_proto_rawDescGZIP(), []int{4} +} + +func (x *QueryUniversalReadRequest) GetRequestId() string { + if x != nil { + return x.RequestId + } + return "" +} + +type QueryUniversalReadResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Read *UniversalRead `protobuf:"bytes,1,opt,name=read,proto3" json:"read,omitempty"` +} + +func (x *QueryUniversalReadResponse) Reset() { + *x = QueryUniversalReadResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_ucallback_v1_query_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *QueryUniversalReadResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*QueryUniversalReadResponse) ProtoMessage() {} + +// Deprecated: Use QueryUniversalReadResponse.ProtoReflect.Descriptor instead. +func (*QueryUniversalReadResponse) Descriptor() ([]byte, []int) { + return file_ucallback_v1_query_proto_rawDescGZIP(), []int{5} +} + +func (x *QueryUniversalReadResponse) GetRead() *UniversalRead { + if x != nil { + return x.Read + } + return nil +} + +type QueryReadsByTxRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + TxHash string `protobuf:"bytes,1,opt,name=tx_hash,json=txHash,proto3" json:"tx_hash,omitempty"` +} + +func (x *QueryReadsByTxRequest) Reset() { + *x = QueryReadsByTxRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_ucallback_v1_query_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *QueryReadsByTxRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*QueryReadsByTxRequest) ProtoMessage() {} + +// Deprecated: Use QueryReadsByTxRequest.ProtoReflect.Descriptor instead. +func (*QueryReadsByTxRequest) Descriptor() ([]byte, []int) { + return file_ucallback_v1_query_proto_rawDescGZIP(), []int{6} +} + +func (x *QueryReadsByTxRequest) GetTxHash() string { + if x != nil { + return x.TxHash + } + return "" +} + +type QueryReadsByTxResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Every read the transaction requested, settled or not, in request-id order. + Reads []*UniversalRead `protobuf:"bytes,1,rep,name=reads,proto3" json:"reads,omitempty"` +} + +func (x *QueryReadsByTxResponse) Reset() { + *x = QueryReadsByTxResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_ucallback_v1_query_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *QueryReadsByTxResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*QueryReadsByTxResponse) ProtoMessage() {} + +// Deprecated: Use QueryReadsByTxResponse.ProtoReflect.Descriptor instead. +func (*QueryReadsByTxResponse) Descriptor() ([]byte, []int) { + return file_ucallback_v1_query_proto_rawDescGZIP(), []int{7} +} + +func (x *QueryReadsByTxResponse) GetReads() []*UniversalRead { + if x != nil { + return x.Reads + } + return nil +} + +type QueryAllAbortedReadRequestsRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Pagination *v1beta1.PageRequest `protobuf:"bytes,1,opt,name=pagination,proto3" json:"pagination,omitempty"` +} + +func (x *QueryAllAbortedReadRequestsRequest) Reset() { + *x = QueryAllAbortedReadRequestsRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_ucallback_v1_query_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *QueryAllAbortedReadRequestsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*QueryAllAbortedReadRequestsRequest) ProtoMessage() {} + +// Deprecated: Use QueryAllAbortedReadRequestsRequest.ProtoReflect.Descriptor instead. +func (*QueryAllAbortedReadRequestsRequest) Descriptor() ([]byte, []int) { + return file_ucallback_v1_query_proto_rawDescGZIP(), []int{8} +} + +func (x *QueryAllAbortedReadRequestsRequest) GetPagination() *v1beta1.PageRequest { + if x != nil { + return x.Pagination + } + return nil +} + +type QueryAllAbortedReadRequestsResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Reads whose expiry call never landed. Each carries error_msg explaining why. + Reads []*UniversalRead `protobuf:"bytes,1,rep,name=reads,proto3" json:"reads,omitempty"` + Pagination *v1beta1.PageResponse `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination,omitempty"` +} + +func (x *QueryAllAbortedReadRequestsResponse) Reset() { + *x = QueryAllAbortedReadRequestsResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_ucallback_v1_query_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *QueryAllAbortedReadRequestsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*QueryAllAbortedReadRequestsResponse) ProtoMessage() {} + +// Deprecated: Use QueryAllAbortedReadRequestsResponse.ProtoReflect.Descriptor instead. +func (*QueryAllAbortedReadRequestsResponse) Descriptor() ([]byte, []int) { + return file_ucallback_v1_query_proto_rawDescGZIP(), []int{9} +} + +func (x *QueryAllAbortedReadRequestsResponse) GetReads() []*UniversalRead { + if x != nil { + return x.Reads + } + return nil +} + +func (x *QueryAllAbortedReadRequestsResponse) GetPagination() *v1beta1.PageResponse { + if x != nil { + return x.Pagination + } + return nil +} + +var File_ucallback_v1_query_proto protoreflect.FileDescriptor + +var file_ucallback_v1_query_proto_rawDesc = []byte{ + 0x0a, 0x18, 0x75, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x2f, 0x76, 0x31, 0x2f, 0x71, + 0x75, 0x65, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0c, 0x75, 0x63, 0x61, 0x6c, + 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x2e, 0x76, 0x31, 0x1a, 0x14, 0x67, 0x6f, 0x67, 0x6f, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x67, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1c, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x2a, 0x63, 0x6f, + 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x62, 0x61, 0x73, 0x65, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2f, + 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1a, 0x75, 0x63, 0x61, 0x6c, 0x6c, 0x62, + 0x61, 0x63, 0x6b, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x65, 0x6e, 0x65, 0x73, 0x69, 0x73, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x18, 0x75, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x2f, + 0x76, 0x31, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x14, + 0x0a, 0x12, 0x51, 0x75, 0x65, 0x72, 0x79, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x22, 0x43, 0x0a, 0x13, 0x51, 0x75, 0x65, 0x72, 0x79, 0x50, 0x61, 0x72, + 0x61, 0x6d, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2c, 0x0a, 0x06, 0x70, + 0x61, 0x72, 0x61, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x75, 0x63, + 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x61, 0x72, 0x61, 0x6d, + 0x73, 0x52, 0x06, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x22, 0x6c, 0x0a, 0x22, 0x51, 0x75, 0x65, + 0x72, 0x79, 0x41, 0x6c, 0x6c, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x61, 0x64, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x46, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x62, 0x61, 0x73, + 0x65, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, + 0x50, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x0a, 0x70, 0x61, 0x67, + 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xa7, 0x01, 0x0a, 0x23, 0x51, 0x75, 0x65, 0x72, + 0x79, 0x41, 0x6c, 0x6c, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x61, 0x64, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x37, 0x0a, 0x05, 0x72, 0x65, 0x61, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, + 0x2e, 0x75, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x6e, + 0x69, 0x76, 0x65, 0x72, 0x73, 0x61, 0x6c, 0x52, 0x65, 0x61, 0x64, 0x42, 0x04, 0xc8, 0xde, 0x1f, + 0x00, 0x52, 0x05, 0x72, 0x65, 0x61, 0x64, 0x73, 0x12, 0x47, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x69, + 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x63, + 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, + 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x50, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x22, 0x3a, 0x0a, 0x19, 0x51, 0x75, 0x65, 0x72, 0x79, 0x55, 0x6e, 0x69, 0x76, 0x65, 0x72, + 0x73, 0x61, 0x6c, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, + 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x22, 0x53, 0x0a, + 0x1a, 0x51, 0x75, 0x65, 0x72, 0x79, 0x55, 0x6e, 0x69, 0x76, 0x65, 0x72, 0x73, 0x61, 0x6c, 0x52, + 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x35, 0x0a, 0x04, 0x72, + 0x65, 0x61, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x75, 0x63, 0x61, 0x6c, + 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x6e, 0x69, 0x76, 0x65, 0x72, 0x73, + 0x61, 0x6c, 0x52, 0x65, 0x61, 0x64, 0x42, 0x04, 0xc8, 0xde, 0x1f, 0x00, 0x52, 0x04, 0x72, 0x65, + 0x61, 0x64, 0x22, 0x30, 0x0a, 0x15, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x61, 0x64, 0x73, + 0x42, 0x79, 0x54, 0x78, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x74, + 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x78, + 0x48, 0x61, 0x73, 0x68, 0x22, 0x51, 0x0a, 0x16, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x61, + 0x64, 0x73, 0x42, 0x79, 0x54, 0x78, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x37, + 0x0a, 0x05, 0x72, 0x65, 0x61, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, + 0x75, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x6e, 0x69, + 0x76, 0x65, 0x72, 0x73, 0x61, 0x6c, 0x52, 0x65, 0x61, 0x64, 0x42, 0x04, 0xc8, 0xde, 0x1f, 0x00, + 0x52, 0x05, 0x72, 0x65, 0x61, 0x64, 0x73, 0x22, 0x6c, 0x0a, 0x22, 0x51, 0x75, 0x65, 0x72, 0x79, + 0x41, 0x6c, 0x6c, 0x41, 0x62, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x46, 0x0a, + 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x26, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x2e, + 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x50, 0x61, + 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xa7, 0x01, 0x0a, 0x23, 0x51, 0x75, 0x65, 0x72, 0x79, 0x41, + 0x6c, 0x6c, 0x41, 0x62, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x37, 0x0a, + 0x05, 0x72, 0x65, 0x61, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x75, + 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x6e, 0x69, 0x76, + 0x65, 0x72, 0x73, 0x61, 0x6c, 0x52, 0x65, 0x61, 0x64, 0x42, 0x04, 0xc8, 0xde, 0x1f, 0x00, 0x52, + 0x05, 0x72, 0x65, 0x61, 0x64, 0x73, 0x12, 0x47, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x63, 0x6f, 0x73, + 0x6d, 0x6f, 0x73, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x76, + 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x50, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x52, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x32, + 0xed, 0x05, 0x0a, 0x05, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x6b, 0x0a, 0x06, 0x50, 0x61, 0x72, + 0x61, 0x6d, 0x73, 0x12, 0x20, 0x2e, 0x75, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x2e, + 0x76, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x75, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, + 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x16, + 0x12, 0x14, 0x2f, 0x75, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x2f, 0x76, 0x31, 0x2f, + 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0xaa, 0x01, 0x0a, 0x16, 0x41, 0x6c, 0x6c, 0x50, 0x65, + 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x73, 0x12, 0x30, 0x2e, 0x75, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x2e, 0x76, 0x31, + 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x41, 0x6c, 0x6c, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, + 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x31, 0x2e, 0x75, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x2e, + 0x76, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x41, 0x6c, 0x6c, 0x50, 0x65, 0x6e, 0x64, 0x69, + 0x6e, 0x67, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x25, 0x12, 0x23, + 0x2f, 0x75, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x65, + 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x72, 0x65, 0x61, 0x64, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x73, 0x12, 0x96, 0x01, 0x0a, 0x0d, 0x55, 0x6e, 0x69, 0x76, 0x65, 0x72, 0x73, 0x61, + 0x6c, 0x52, 0x65, 0x61, 0x64, 0x12, 0x27, 0x2e, 0x75, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, + 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x55, 0x6e, 0x69, 0x76, 0x65, 0x72, + 0x73, 0x61, 0x6c, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, + 0x2e, 0x75, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x51, 0x75, + 0x65, 0x72, 0x79, 0x55, 0x6e, 0x69, 0x76, 0x65, 0x72, 0x73, 0x61, 0x6c, 0x52, 0x65, 0x61, 0x64, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x32, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2c, + 0x12, 0x2a, 0x2f, 0x75, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x2f, 0x76, 0x31, 0x2f, + 0x75, 0x6e, 0x69, 0x76, 0x65, 0x72, 0x73, 0x61, 0x6c, 0x5f, 0x72, 0x65, 0x61, 0x64, 0x73, 0x2f, + 0x7b, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x7d, 0x12, 0xaa, 0x01, 0x0a, + 0x16, 0x41, 0x6c, 0x6c, 0x41, 0x62, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x52, 0x65, 0x61, 0x64, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x12, 0x30, 0x2e, 0x75, 0x63, 0x61, 0x6c, 0x6c, 0x62, + 0x61, 0x63, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x41, 0x6c, 0x6c, 0x41, + 0x62, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x31, 0x2e, 0x75, 0x63, 0x61, 0x6c, + 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x41, 0x6c, + 0x6c, 0x41, 0x62, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2b, 0x82, 0xd3, + 0xe4, 0x93, 0x02, 0x25, 0x12, 0x23, 0x2f, 0x75, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, + 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x62, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x61, 0x64, + 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x12, 0x83, 0x01, 0x0a, 0x09, 0x52, 0x65, + 0x61, 0x64, 0x73, 0x42, 0x79, 0x54, 0x78, 0x12, 0x23, 0x2e, 0x75, 0x63, 0x61, 0x6c, 0x6c, 0x62, + 0x61, 0x63, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x61, 0x64, + 0x73, 0x42, 0x79, 0x54, 0x78, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x75, + 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, + 0x79, 0x52, 0x65, 0x61, 0x64, 0x73, 0x42, 0x79, 0x54, 0x78, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x2b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x25, 0x12, 0x23, 0x2f, 0x75, 0x63, 0x61, + 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x65, 0x61, 0x64, 0x73, 0x5f, + 0x62, 0x79, 0x5f, 0x74, 0x78, 0x2f, 0x7b, 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x7d, 0x42, + 0xb2, 0x01, 0x0a, 0x10, 0x63, 0x6f, 0x6d, 0x2e, 0x75, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, + 0x6b, 0x2e, 0x76, 0x31, 0x42, 0x0a, 0x51, 0x75, 0x65, 0x72, 0x79, 0x50, 0x72, 0x6f, 0x74, 0x6f, + 0x50, 0x01, 0x5a, 0x41, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, + 0x75, 0x73, 0x68, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x2f, 0x70, 0x75, 0x73, 0x68, 0x2d, 0x63, 0x68, + 0x61, 0x69, 0x6e, 0x2d, 0x6e, 0x6f, 0x64, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x75, 0x63, 0x61, + 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x2f, 0x76, 0x31, 0x3b, 0x75, 0x63, 0x61, 0x6c, 0x6c, 0x62, + 0x61, 0x63, 0x6b, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x55, 0x58, 0x58, 0xaa, 0x02, 0x0c, 0x55, 0x63, + 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x0c, 0x55, 0x63, 0x61, + 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x18, 0x55, 0x63, 0x61, 0x6c, + 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0d, 0x55, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, + 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_ucallback_v1_query_proto_rawDescOnce sync.Once + file_ucallback_v1_query_proto_rawDescData = file_ucallback_v1_query_proto_rawDesc +) + +func file_ucallback_v1_query_proto_rawDescGZIP() []byte { + file_ucallback_v1_query_proto_rawDescOnce.Do(func() { + file_ucallback_v1_query_proto_rawDescData = protoimpl.X.CompressGZIP(file_ucallback_v1_query_proto_rawDescData) + }) + return file_ucallback_v1_query_proto_rawDescData +} + +var file_ucallback_v1_query_proto_msgTypes = make([]protoimpl.MessageInfo, 10) +var file_ucallback_v1_query_proto_goTypes = []interface{}{ + (*QueryParamsRequest)(nil), // 0: ucallback.v1.QueryParamsRequest + (*QueryParamsResponse)(nil), // 1: ucallback.v1.QueryParamsResponse + (*QueryAllPendingReadRequestsRequest)(nil), // 2: ucallback.v1.QueryAllPendingReadRequestsRequest + (*QueryAllPendingReadRequestsResponse)(nil), // 3: ucallback.v1.QueryAllPendingReadRequestsResponse + (*QueryUniversalReadRequest)(nil), // 4: ucallback.v1.QueryUniversalReadRequest + (*QueryUniversalReadResponse)(nil), // 5: ucallback.v1.QueryUniversalReadResponse + (*QueryReadsByTxRequest)(nil), // 6: ucallback.v1.QueryReadsByTxRequest + (*QueryReadsByTxResponse)(nil), // 7: ucallback.v1.QueryReadsByTxResponse + (*QueryAllAbortedReadRequestsRequest)(nil), // 8: ucallback.v1.QueryAllAbortedReadRequestsRequest + (*QueryAllAbortedReadRequestsResponse)(nil), // 9: ucallback.v1.QueryAllAbortedReadRequestsResponse + (*Params)(nil), // 10: ucallback.v1.Params + (*v1beta1.PageRequest)(nil), // 11: cosmos.base.query.v1beta1.PageRequest + (*UniversalRead)(nil), // 12: ucallback.v1.UniversalRead + (*v1beta1.PageResponse)(nil), // 13: cosmos.base.query.v1beta1.PageResponse +} +var file_ucallback_v1_query_proto_depIdxs = []int32{ + 10, // 0: ucallback.v1.QueryParamsResponse.params:type_name -> ucallback.v1.Params + 11, // 1: ucallback.v1.QueryAllPendingReadRequestsRequest.pagination:type_name -> cosmos.base.query.v1beta1.PageRequest + 12, // 2: ucallback.v1.QueryAllPendingReadRequestsResponse.reads:type_name -> ucallback.v1.UniversalRead + 13, // 3: ucallback.v1.QueryAllPendingReadRequestsResponse.pagination:type_name -> cosmos.base.query.v1beta1.PageResponse + 12, // 4: ucallback.v1.QueryUniversalReadResponse.read:type_name -> ucallback.v1.UniversalRead + 12, // 5: ucallback.v1.QueryReadsByTxResponse.reads:type_name -> ucallback.v1.UniversalRead + 11, // 6: ucallback.v1.QueryAllAbortedReadRequestsRequest.pagination:type_name -> cosmos.base.query.v1beta1.PageRequest + 12, // 7: ucallback.v1.QueryAllAbortedReadRequestsResponse.reads:type_name -> ucallback.v1.UniversalRead + 13, // 8: ucallback.v1.QueryAllAbortedReadRequestsResponse.pagination:type_name -> cosmos.base.query.v1beta1.PageResponse + 0, // 9: ucallback.v1.Query.Params:input_type -> ucallback.v1.QueryParamsRequest + 2, // 10: ucallback.v1.Query.AllPendingReadRequests:input_type -> ucallback.v1.QueryAllPendingReadRequestsRequest + 4, // 11: ucallback.v1.Query.UniversalRead:input_type -> ucallback.v1.QueryUniversalReadRequest + 8, // 12: ucallback.v1.Query.AllAbortedReadRequests:input_type -> ucallback.v1.QueryAllAbortedReadRequestsRequest + 6, // 13: ucallback.v1.Query.ReadsByTx:input_type -> ucallback.v1.QueryReadsByTxRequest + 1, // 14: ucallback.v1.Query.Params:output_type -> ucallback.v1.QueryParamsResponse + 3, // 15: ucallback.v1.Query.AllPendingReadRequests:output_type -> ucallback.v1.QueryAllPendingReadRequestsResponse + 5, // 16: ucallback.v1.Query.UniversalRead:output_type -> ucallback.v1.QueryUniversalReadResponse + 9, // 17: ucallback.v1.Query.AllAbortedReadRequests:output_type -> ucallback.v1.QueryAllAbortedReadRequestsResponse + 7, // 18: ucallback.v1.Query.ReadsByTx:output_type -> ucallback.v1.QueryReadsByTxResponse + 14, // [14:19] is the sub-list for method output_type + 9, // [9:14] is the sub-list for method input_type + 9, // [9:9] is the sub-list for extension type_name + 9, // [9:9] is the sub-list for extension extendee + 0, // [0:9] is the sub-list for field type_name +} + +func init() { file_ucallback_v1_query_proto_init() } +func file_ucallback_v1_query_proto_init() { + if File_ucallback_v1_query_proto != nil { + return + } + file_ucallback_v1_genesis_proto_init() + file_ucallback_v1_types_proto_init() + if !protoimpl.UnsafeEnabled { + file_ucallback_v1_query_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*QueryParamsRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ucallback_v1_query_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*QueryParamsResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ucallback_v1_query_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*QueryAllPendingReadRequestsRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ucallback_v1_query_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*QueryAllPendingReadRequestsResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ucallback_v1_query_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*QueryUniversalReadRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ucallback_v1_query_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*QueryUniversalReadResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ucallback_v1_query_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*QueryReadsByTxRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ucallback_v1_query_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*QueryReadsByTxResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ucallback_v1_query_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*QueryAllAbortedReadRequestsRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ucallback_v1_query_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*QueryAllAbortedReadRequestsResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_ucallback_v1_query_proto_rawDesc, + NumEnums: 0, + NumMessages: 10, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_ucallback_v1_query_proto_goTypes, + DependencyIndexes: file_ucallback_v1_query_proto_depIdxs, + MessageInfos: file_ucallback_v1_query_proto_msgTypes, + }.Build() + File_ucallback_v1_query_proto = out.File + file_ucallback_v1_query_proto_rawDesc = nil + file_ucallback_v1_query_proto_goTypes = nil + file_ucallback_v1_query_proto_depIdxs = nil +} diff --git a/api/ucallback/v1/query_grpc.pb.go b/api/ucallback/v1/query_grpc.pb.go new file mode 100644 index 00000000..3fa0d5f0 --- /dev/null +++ b/api/ucallback/v1/query_grpc.pb.go @@ -0,0 +1,275 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.3.0 +// - protoc (unknown) +// source: ucallback/v1/query.proto + +package ucallbackv1 + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.32.0 or later. +const _ = grpc.SupportPackageIsVersion7 + +const ( + Query_Params_FullMethodName = "/ucallback.v1.Query/Params" + Query_AllPendingReadRequests_FullMethodName = "/ucallback.v1.Query/AllPendingReadRequests" + Query_UniversalRead_FullMethodName = "/ucallback.v1.Query/UniversalRead" + Query_AllAbortedReadRequests_FullMethodName = "/ucallback.v1.Query/AllAbortedReadRequests" + Query_ReadsByTx_FullMethodName = "/ucallback.v1.Query/ReadsByTx" +) + +// QueryClient is the client API for Query service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type QueryClient interface { + // Params queries all parameters of the module. + Params(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error) + // AllPendingReadRequests lists read requests still awaiting an observation. + // This is the endpoint universal validators poll. + AllPendingReadRequests(ctx context.Context, in *QueryAllPendingReadRequestsRequest, opts ...grpc.CallOption) (*QueryAllPendingReadRequestsResponse, error) + // UniversalRead returns one read by request id, at any point in its lifecycle. + UniversalRead(ctx context.Context, in *QueryUniversalReadRequest, opts ...grpc.CallOption) (*QueryUniversalReadResponse, error) + // AllAbortedReadRequests lists reads the chain gave up on. These need manual + // intervention: the contract may still hold them as pending and the funder's + // refund is unsettled. + AllAbortedReadRequests(ctx context.Context, in *QueryAllAbortedReadRequestsRequest, opts ...grpc.CallOption) (*QueryAllAbortedReadRequestsResponse, error) + // ReadsByTxHash returns every read requested by one Push transaction. A single + // transaction can emit several ReadRequested logs; this reassembles that batch. + ReadsByTx(ctx context.Context, in *QueryReadsByTxRequest, opts ...grpc.CallOption) (*QueryReadsByTxResponse, error) +} + +type queryClient struct { + cc grpc.ClientConnInterface +} + +func NewQueryClient(cc grpc.ClientConnInterface) QueryClient { + return &queryClient{cc} +} + +func (c *queryClient) Params(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error) { + out := new(QueryParamsResponse) + err := c.cc.Invoke(ctx, Query_Params_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) AllPendingReadRequests(ctx context.Context, in *QueryAllPendingReadRequestsRequest, opts ...grpc.CallOption) (*QueryAllPendingReadRequestsResponse, error) { + out := new(QueryAllPendingReadRequestsResponse) + err := c.cc.Invoke(ctx, Query_AllPendingReadRequests_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) UniversalRead(ctx context.Context, in *QueryUniversalReadRequest, opts ...grpc.CallOption) (*QueryUniversalReadResponse, error) { + out := new(QueryUniversalReadResponse) + err := c.cc.Invoke(ctx, Query_UniversalRead_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) AllAbortedReadRequests(ctx context.Context, in *QueryAllAbortedReadRequestsRequest, opts ...grpc.CallOption) (*QueryAllAbortedReadRequestsResponse, error) { + out := new(QueryAllAbortedReadRequestsResponse) + err := c.cc.Invoke(ctx, Query_AllAbortedReadRequests_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) ReadsByTx(ctx context.Context, in *QueryReadsByTxRequest, opts ...grpc.CallOption) (*QueryReadsByTxResponse, error) { + out := new(QueryReadsByTxResponse) + err := c.cc.Invoke(ctx, Query_ReadsByTx_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// QueryServer is the server API for Query service. +// All implementations must embed UnimplementedQueryServer +// for forward compatibility +type QueryServer interface { + // Params queries all parameters of the module. + Params(context.Context, *QueryParamsRequest) (*QueryParamsResponse, error) + // AllPendingReadRequests lists read requests still awaiting an observation. + // This is the endpoint universal validators poll. + AllPendingReadRequests(context.Context, *QueryAllPendingReadRequestsRequest) (*QueryAllPendingReadRequestsResponse, error) + // UniversalRead returns one read by request id, at any point in its lifecycle. + UniversalRead(context.Context, *QueryUniversalReadRequest) (*QueryUniversalReadResponse, error) + // AllAbortedReadRequests lists reads the chain gave up on. These need manual + // intervention: the contract may still hold them as pending and the funder's + // refund is unsettled. + AllAbortedReadRequests(context.Context, *QueryAllAbortedReadRequestsRequest) (*QueryAllAbortedReadRequestsResponse, error) + // ReadsByTxHash returns every read requested by one Push transaction. A single + // transaction can emit several ReadRequested logs; this reassembles that batch. + ReadsByTx(context.Context, *QueryReadsByTxRequest) (*QueryReadsByTxResponse, error) + mustEmbedUnimplementedQueryServer() +} + +// UnimplementedQueryServer must be embedded to have forward compatible implementations. +type UnimplementedQueryServer struct { +} + +func (UnimplementedQueryServer) Params(context.Context, *QueryParamsRequest) (*QueryParamsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Params not implemented") +} +func (UnimplementedQueryServer) AllPendingReadRequests(context.Context, *QueryAllPendingReadRequestsRequest) (*QueryAllPendingReadRequestsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method AllPendingReadRequests not implemented") +} +func (UnimplementedQueryServer) UniversalRead(context.Context, *QueryUniversalReadRequest) (*QueryUniversalReadResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method UniversalRead not implemented") +} +func (UnimplementedQueryServer) AllAbortedReadRequests(context.Context, *QueryAllAbortedReadRequestsRequest) (*QueryAllAbortedReadRequestsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method AllAbortedReadRequests not implemented") +} +func (UnimplementedQueryServer) ReadsByTx(context.Context, *QueryReadsByTxRequest) (*QueryReadsByTxResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ReadsByTx not implemented") +} +func (UnimplementedQueryServer) mustEmbedUnimplementedQueryServer() {} + +// UnsafeQueryServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to QueryServer will +// result in compilation errors. +type UnsafeQueryServer interface { + mustEmbedUnimplementedQueryServer() +} + +func RegisterQueryServer(s grpc.ServiceRegistrar, srv QueryServer) { + s.RegisterService(&Query_ServiceDesc, srv) +} + +func _Query_Params_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryParamsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).Params(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Query_Params_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).Params(ctx, req.(*QueryParamsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_AllPendingReadRequests_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryAllPendingReadRequestsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).AllPendingReadRequests(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Query_AllPendingReadRequests_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).AllPendingReadRequests(ctx, req.(*QueryAllPendingReadRequestsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_UniversalRead_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryUniversalReadRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).UniversalRead(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Query_UniversalRead_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).UniversalRead(ctx, req.(*QueryUniversalReadRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_AllAbortedReadRequests_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryAllAbortedReadRequestsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).AllAbortedReadRequests(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Query_AllAbortedReadRequests_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).AllAbortedReadRequests(ctx, req.(*QueryAllAbortedReadRequestsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_ReadsByTx_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryReadsByTxRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).ReadsByTx(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Query_ReadsByTx_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).ReadsByTx(ctx, req.(*QueryReadsByTxRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// Query_ServiceDesc is the grpc.ServiceDesc for Query service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var Query_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "ucallback.v1.Query", + HandlerType: (*QueryServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Params", + Handler: _Query_Params_Handler, + }, + { + MethodName: "AllPendingReadRequests", + Handler: _Query_AllPendingReadRequests_Handler, + }, + { + MethodName: "UniversalRead", + Handler: _Query_UniversalRead_Handler, + }, + { + MethodName: "AllAbortedReadRequests", + Handler: _Query_AllAbortedReadRequests_Handler, + }, + { + MethodName: "ReadsByTx", + Handler: _Query_ReadsByTx_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "ucallback/v1/query.proto", +} diff --git a/api/ucallback/v1/tx.pulsar.go b/api/ucallback/v1/tx.pulsar.go new file mode 100644 index 00000000..fe00f0f5 --- /dev/null +++ b/api/ucallback/v1/tx.pulsar.go @@ -0,0 +1,3249 @@ +// Code generated by protoc-gen-go-pulsar. DO NOT EDIT. +package ucallbackv1 + +import ( + _ "cosmossdk.io/api/amino" + _ "cosmossdk.io/api/cosmos/msg/v1" + fmt "fmt" + _ "github.com/cosmos/cosmos-proto" + runtime "github.com/cosmos/cosmos-proto/runtime" + _ "github.com/cosmos/gogoproto/gogoproto" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoiface "google.golang.org/protobuf/runtime/protoiface" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" +) + +var ( + md_MsgUpdateParams protoreflect.MessageDescriptor + fd_MsgUpdateParams_authority protoreflect.FieldDescriptor + fd_MsgUpdateParams_params protoreflect.FieldDescriptor +) + +func init() { + file_ucallback_v1_tx_proto_init() + md_MsgUpdateParams = File_ucallback_v1_tx_proto.Messages().ByName("MsgUpdateParams") + fd_MsgUpdateParams_authority = md_MsgUpdateParams.Fields().ByName("authority") + fd_MsgUpdateParams_params = md_MsgUpdateParams.Fields().ByName("params") +} + +var _ protoreflect.Message = (*fastReflection_MsgUpdateParams)(nil) + +type fastReflection_MsgUpdateParams MsgUpdateParams + +func (x *MsgUpdateParams) ProtoReflect() protoreflect.Message { + return (*fastReflection_MsgUpdateParams)(x) +} + +func (x *MsgUpdateParams) slowProtoReflect() protoreflect.Message { + mi := &file_ucallback_v1_tx_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +var _fastReflection_MsgUpdateParams_messageType fastReflection_MsgUpdateParams_messageType +var _ protoreflect.MessageType = fastReflection_MsgUpdateParams_messageType{} + +type fastReflection_MsgUpdateParams_messageType struct{} + +func (x fastReflection_MsgUpdateParams_messageType) Zero() protoreflect.Message { + return (*fastReflection_MsgUpdateParams)(nil) +} +func (x fastReflection_MsgUpdateParams_messageType) New() protoreflect.Message { + return new(fastReflection_MsgUpdateParams) +} +func (x fastReflection_MsgUpdateParams_messageType) Descriptor() protoreflect.MessageDescriptor { + return md_MsgUpdateParams +} + +// Descriptor returns message descriptor, which contains only the protobuf +// type information for the message. +func (x *fastReflection_MsgUpdateParams) Descriptor() protoreflect.MessageDescriptor { + return md_MsgUpdateParams +} + +// Type returns the message type, which encapsulates both Go and protobuf +// type information. If the Go type information is not needed, +// it is recommended that the message descriptor be used instead. +func (x *fastReflection_MsgUpdateParams) Type() protoreflect.MessageType { + return _fastReflection_MsgUpdateParams_messageType +} + +// New returns a newly allocated and mutable empty message. +func (x *fastReflection_MsgUpdateParams) New() protoreflect.Message { + return new(fastReflection_MsgUpdateParams) +} + +// Interface unwraps the message reflection interface and +// returns the underlying ProtoMessage interface. +func (x *fastReflection_MsgUpdateParams) Interface() protoreflect.ProtoMessage { + return (*MsgUpdateParams)(x) +} + +// Range iterates over every populated field in an undefined order, +// calling f for each field descriptor and value encountered. +// Range returns immediately if f returns false. +// While iterating, mutating operations may only be performed +// on the current field descriptor. +func (x *fastReflection_MsgUpdateParams) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { + if x.Authority != "" { + value := protoreflect.ValueOfString(x.Authority) + if !f(fd_MsgUpdateParams_authority, value) { + return + } + } + if x.Params != nil { + value := protoreflect.ValueOfMessage(x.Params.ProtoReflect()) + if !f(fd_MsgUpdateParams_params, value) { + return + } + } +} + +// Has reports whether a field is populated. +// +// Some fields have the property of nullability where it is possible to +// distinguish between the default value of a field and whether the field +// was explicitly populated with the default value. Singular message fields, +// member fields of a oneof, and proto2 scalar fields are nullable. Such +// fields are populated only if explicitly set. +// +// In other cases (aside from the nullable cases above), +// a proto3 scalar field is populated if it contains a non-zero value, and +// a repeated field is populated if it is non-empty. +func (x *fastReflection_MsgUpdateParams) Has(fd protoreflect.FieldDescriptor) bool { + switch fd.FullName() { + case "ucallback.v1.MsgUpdateParams.authority": + return x.Authority != "" + case "ucallback.v1.MsgUpdateParams.params": + return x.Params != nil + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.MsgUpdateParams")) + } + panic(fmt.Errorf("message ucallback.v1.MsgUpdateParams does not contain field %s", fd.FullName())) + } +} + +// Clear clears the field such that a subsequent Has call reports false. +// +// Clearing an extension field clears both the extension type and value +// associated with the given field number. +// +// Clear is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_MsgUpdateParams) Clear(fd protoreflect.FieldDescriptor) { + switch fd.FullName() { + case "ucallback.v1.MsgUpdateParams.authority": + x.Authority = "" + case "ucallback.v1.MsgUpdateParams.params": + x.Params = nil + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.MsgUpdateParams")) + } + panic(fmt.Errorf("message ucallback.v1.MsgUpdateParams does not contain field %s", fd.FullName())) + } +} + +// Get retrieves the value for a field. +// +// For unpopulated scalars, it returns the default value, where +// the default value of a bytes scalar is guaranteed to be a copy. +// For unpopulated composite types, it returns an empty, read-only view +// of the value; to obtain a mutable reference, use Mutable. +func (x *fastReflection_MsgUpdateParams) Get(descriptor protoreflect.FieldDescriptor) protoreflect.Value { + switch descriptor.FullName() { + case "ucallback.v1.MsgUpdateParams.authority": + value := x.Authority + return protoreflect.ValueOfString(value) + case "ucallback.v1.MsgUpdateParams.params": + value := x.Params + return protoreflect.ValueOfMessage(value.ProtoReflect()) + default: + if descriptor.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.MsgUpdateParams")) + } + panic(fmt.Errorf("message ucallback.v1.MsgUpdateParams does not contain field %s", descriptor.FullName())) + } +} + +// Set stores the value for a field. +// +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType. +// When setting a composite type, it is unspecified whether the stored value +// aliases the source's memory in any way. If the composite value is an +// empty, read-only value, then it panics. +// +// Set is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_MsgUpdateParams) Set(fd protoreflect.FieldDescriptor, value protoreflect.Value) { + switch fd.FullName() { + case "ucallback.v1.MsgUpdateParams.authority": + x.Authority = value.Interface().(string) + case "ucallback.v1.MsgUpdateParams.params": + x.Params = value.Message().Interface().(*Params) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.MsgUpdateParams")) + } + panic(fmt.Errorf("message ucallback.v1.MsgUpdateParams does not contain field %s", fd.FullName())) + } +} + +// Mutable returns a mutable reference to a composite type. +// +// If the field is unpopulated, it may allocate a composite value. +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType +// if not already stored. +// It panics if the field does not contain a composite type. +// +// Mutable is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_MsgUpdateParams) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "ucallback.v1.MsgUpdateParams.params": + if x.Params == nil { + x.Params = new(Params) + } + return protoreflect.ValueOfMessage(x.Params.ProtoReflect()) + case "ucallback.v1.MsgUpdateParams.authority": + panic(fmt.Errorf("field authority of message ucallback.v1.MsgUpdateParams is not mutable")) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.MsgUpdateParams")) + } + panic(fmt.Errorf("message ucallback.v1.MsgUpdateParams does not contain field %s", fd.FullName())) + } +} + +// NewField returns a new value that is assignable to the field +// for the given descriptor. For scalars, this returns the default value. +// For lists, maps, and messages, this returns a new, empty, mutable value. +func (x *fastReflection_MsgUpdateParams) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "ucallback.v1.MsgUpdateParams.authority": + return protoreflect.ValueOfString("") + case "ucallback.v1.MsgUpdateParams.params": + m := new(Params) + return protoreflect.ValueOfMessage(m.ProtoReflect()) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.MsgUpdateParams")) + } + panic(fmt.Errorf("message ucallback.v1.MsgUpdateParams does not contain field %s", fd.FullName())) + } +} + +// WhichOneof reports which field within the oneof is populated, +// returning nil if none are populated. +// It panics if the oneof descriptor does not belong to this message. +func (x *fastReflection_MsgUpdateParams) WhichOneof(d protoreflect.OneofDescriptor) protoreflect.FieldDescriptor { + switch d.FullName() { + default: + panic(fmt.Errorf("%s is not a oneof field in ucallback.v1.MsgUpdateParams", d.FullName())) + } + panic("unreachable") +} + +// GetUnknown retrieves the entire list of unknown fields. +// The caller may only mutate the contents of the RawFields +// if the mutated bytes are stored back into the message with SetUnknown. +func (x *fastReflection_MsgUpdateParams) GetUnknown() protoreflect.RawFields { + return x.unknownFields +} + +// SetUnknown stores an entire list of unknown fields. +// The raw fields must be syntactically valid according to the wire format. +// An implementation may panic if this is not the case. +// Once stored, the caller must not mutate the content of the RawFields. +// An empty RawFields may be passed to clear the fields. +// +// SetUnknown is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_MsgUpdateParams) SetUnknown(fields protoreflect.RawFields) { + x.unknownFields = fields +} + +// IsValid reports whether the message is valid. +// +// An invalid message is an empty, read-only value. +// +// An invalid message often corresponds to a nil pointer of the concrete +// message type, but the details are implementation dependent. +// Validity is not part of the protobuf data model, and may not +// be preserved in marshaling or other operations. +func (x *fastReflection_MsgUpdateParams) IsValid() bool { + return x != nil +} + +// ProtoMethods returns optional fastReflectionFeature-path implementations of various operations. +// This method may return nil. +// +// The returned methods type is identical to +// "google.golang.org/protobuf/runtime/protoiface".Methods. +// Consult the protoiface package documentation for details. +func (x *fastReflection_MsgUpdateParams) ProtoMethods() *protoiface.Methods { + size := func(input protoiface.SizeInput) protoiface.SizeOutput { + x := input.Message.Interface().(*MsgUpdateParams) + if x == nil { + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: 0, + } + } + options := runtime.SizeInputToOptions(input) + _ = options + var n int + var l int + _ = l + l = len(x.Authority) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } + if x.Params != nil { + l = options.Size(x.Params) + n += 1 + l + runtime.Sov(uint64(l)) + } + if x.unknownFields != nil { + n += len(x.unknownFields) + } + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: n, + } + } + + marshal := func(input protoiface.MarshalInput) (protoiface.MarshalOutput, error) { + x := input.Message.Interface().(*MsgUpdateParams) + if x == nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + options := runtime.MarshalInputToOptions(input) + _ = options + size := options.Size(x) + dAtA := make([]byte, size) + i := len(dAtA) + _ = i + var l int + _ = l + if x.unknownFields != nil { + i -= len(x.unknownFields) + copy(dAtA[i:], x.unknownFields) + } + if x.Params != nil { + encoded, err := options.Marshal(x.Params) + if err != nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, err + } + i -= len(encoded) + copy(dAtA[i:], encoded) + i = runtime.EncodeVarint(dAtA, i, uint64(len(encoded))) + i-- + dAtA[i] = 0x12 + } + if len(x.Authority) > 0 { + i -= len(x.Authority) + copy(dAtA[i:], x.Authority) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.Authority))) + i-- + dAtA[i] = 0xa + } + if input.Buf != nil { + input.Buf = append(input.Buf, dAtA...) + } else { + input.Buf = dAtA + } + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + unmarshal := func(input protoiface.UnmarshalInput) (protoiface.UnmarshalOutput, error) { + x := input.Message.Interface().(*MsgUpdateParams) + if x == nil { + return protoiface.UnmarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Flags: input.Flags, + }, nil + } + options := runtime.UnmarshalInputToOptions(input) + _ = options + dAtA := input.Buf + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: MsgUpdateParams: wiretype end group for non-group") + } + if fieldNum <= 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: MsgUpdateParams: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Authority", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.Authority = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Params", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if x.Params == nil { + x.Params = &Params{} + } + if err := options.Unmarshal(dAtA[iNdEx:postIndex], x.Params); err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := runtime.Skip(dAtA[iNdEx:]) + if err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if !options.DiscardUnknown { + x.unknownFields = append(x.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + } + iNdEx += skippy + } + } + + if iNdEx > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, nil + } + return &protoiface.Methods{ + NoUnkeyedLiterals: struct{}{}, + Flags: protoiface.SupportMarshalDeterministic | protoiface.SupportUnmarshalDiscardUnknown, + Size: size, + Marshal: marshal, + Unmarshal: unmarshal, + Merge: nil, + CheckInitialized: nil, + } +} + +var ( + md_MsgUpdateParamsResponse protoreflect.MessageDescriptor +) + +func init() { + file_ucallback_v1_tx_proto_init() + md_MsgUpdateParamsResponse = File_ucallback_v1_tx_proto.Messages().ByName("MsgUpdateParamsResponse") +} + +var _ protoreflect.Message = (*fastReflection_MsgUpdateParamsResponse)(nil) + +type fastReflection_MsgUpdateParamsResponse MsgUpdateParamsResponse + +func (x *MsgUpdateParamsResponse) ProtoReflect() protoreflect.Message { + return (*fastReflection_MsgUpdateParamsResponse)(x) +} + +func (x *MsgUpdateParamsResponse) slowProtoReflect() protoreflect.Message { + mi := &file_ucallback_v1_tx_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +var _fastReflection_MsgUpdateParamsResponse_messageType fastReflection_MsgUpdateParamsResponse_messageType +var _ protoreflect.MessageType = fastReflection_MsgUpdateParamsResponse_messageType{} + +type fastReflection_MsgUpdateParamsResponse_messageType struct{} + +func (x fastReflection_MsgUpdateParamsResponse_messageType) Zero() protoreflect.Message { + return (*fastReflection_MsgUpdateParamsResponse)(nil) +} +func (x fastReflection_MsgUpdateParamsResponse_messageType) New() protoreflect.Message { + return new(fastReflection_MsgUpdateParamsResponse) +} +func (x fastReflection_MsgUpdateParamsResponse_messageType) Descriptor() protoreflect.MessageDescriptor { + return md_MsgUpdateParamsResponse +} + +// Descriptor returns message descriptor, which contains only the protobuf +// type information for the message. +func (x *fastReflection_MsgUpdateParamsResponse) Descriptor() protoreflect.MessageDescriptor { + return md_MsgUpdateParamsResponse +} + +// Type returns the message type, which encapsulates both Go and protobuf +// type information. If the Go type information is not needed, +// it is recommended that the message descriptor be used instead. +func (x *fastReflection_MsgUpdateParamsResponse) Type() protoreflect.MessageType { + return _fastReflection_MsgUpdateParamsResponse_messageType +} + +// New returns a newly allocated and mutable empty message. +func (x *fastReflection_MsgUpdateParamsResponse) New() protoreflect.Message { + return new(fastReflection_MsgUpdateParamsResponse) +} + +// Interface unwraps the message reflection interface and +// returns the underlying ProtoMessage interface. +func (x *fastReflection_MsgUpdateParamsResponse) Interface() protoreflect.ProtoMessage { + return (*MsgUpdateParamsResponse)(x) +} + +// Range iterates over every populated field in an undefined order, +// calling f for each field descriptor and value encountered. +// Range returns immediately if f returns false. +// While iterating, mutating operations may only be performed +// on the current field descriptor. +func (x *fastReflection_MsgUpdateParamsResponse) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { +} + +// Has reports whether a field is populated. +// +// Some fields have the property of nullability where it is possible to +// distinguish between the default value of a field and whether the field +// was explicitly populated with the default value. Singular message fields, +// member fields of a oneof, and proto2 scalar fields are nullable. Such +// fields are populated only if explicitly set. +// +// In other cases (aside from the nullable cases above), +// a proto3 scalar field is populated if it contains a non-zero value, and +// a repeated field is populated if it is non-empty. +func (x *fastReflection_MsgUpdateParamsResponse) Has(fd protoreflect.FieldDescriptor) bool { + switch fd.FullName() { + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.MsgUpdateParamsResponse")) + } + panic(fmt.Errorf("message ucallback.v1.MsgUpdateParamsResponse does not contain field %s", fd.FullName())) + } +} + +// Clear clears the field such that a subsequent Has call reports false. +// +// Clearing an extension field clears both the extension type and value +// associated with the given field number. +// +// Clear is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_MsgUpdateParamsResponse) Clear(fd protoreflect.FieldDescriptor) { + switch fd.FullName() { + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.MsgUpdateParamsResponse")) + } + panic(fmt.Errorf("message ucallback.v1.MsgUpdateParamsResponse does not contain field %s", fd.FullName())) + } +} + +// Get retrieves the value for a field. +// +// For unpopulated scalars, it returns the default value, where +// the default value of a bytes scalar is guaranteed to be a copy. +// For unpopulated composite types, it returns an empty, read-only view +// of the value; to obtain a mutable reference, use Mutable. +func (x *fastReflection_MsgUpdateParamsResponse) Get(descriptor protoreflect.FieldDescriptor) protoreflect.Value { + switch descriptor.FullName() { + default: + if descriptor.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.MsgUpdateParamsResponse")) + } + panic(fmt.Errorf("message ucallback.v1.MsgUpdateParamsResponse does not contain field %s", descriptor.FullName())) + } +} + +// Set stores the value for a field. +// +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType. +// When setting a composite type, it is unspecified whether the stored value +// aliases the source's memory in any way. If the composite value is an +// empty, read-only value, then it panics. +// +// Set is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_MsgUpdateParamsResponse) Set(fd protoreflect.FieldDescriptor, value protoreflect.Value) { + switch fd.FullName() { + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.MsgUpdateParamsResponse")) + } + panic(fmt.Errorf("message ucallback.v1.MsgUpdateParamsResponse does not contain field %s", fd.FullName())) + } +} + +// Mutable returns a mutable reference to a composite type. +// +// If the field is unpopulated, it may allocate a composite value. +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType +// if not already stored. +// It panics if the field does not contain a composite type. +// +// Mutable is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_MsgUpdateParamsResponse) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.MsgUpdateParamsResponse")) + } + panic(fmt.Errorf("message ucallback.v1.MsgUpdateParamsResponse does not contain field %s", fd.FullName())) + } +} + +// NewField returns a new value that is assignable to the field +// for the given descriptor. For scalars, this returns the default value. +// For lists, maps, and messages, this returns a new, empty, mutable value. +func (x *fastReflection_MsgUpdateParamsResponse) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.MsgUpdateParamsResponse")) + } + panic(fmt.Errorf("message ucallback.v1.MsgUpdateParamsResponse does not contain field %s", fd.FullName())) + } +} + +// WhichOneof reports which field within the oneof is populated, +// returning nil if none are populated. +// It panics if the oneof descriptor does not belong to this message. +func (x *fastReflection_MsgUpdateParamsResponse) WhichOneof(d protoreflect.OneofDescriptor) protoreflect.FieldDescriptor { + switch d.FullName() { + default: + panic(fmt.Errorf("%s is not a oneof field in ucallback.v1.MsgUpdateParamsResponse", d.FullName())) + } + panic("unreachable") +} + +// GetUnknown retrieves the entire list of unknown fields. +// The caller may only mutate the contents of the RawFields +// if the mutated bytes are stored back into the message with SetUnknown. +func (x *fastReflection_MsgUpdateParamsResponse) GetUnknown() protoreflect.RawFields { + return x.unknownFields +} + +// SetUnknown stores an entire list of unknown fields. +// The raw fields must be syntactically valid according to the wire format. +// An implementation may panic if this is not the case. +// Once stored, the caller must not mutate the content of the RawFields. +// An empty RawFields may be passed to clear the fields. +// +// SetUnknown is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_MsgUpdateParamsResponse) SetUnknown(fields protoreflect.RawFields) { + x.unknownFields = fields +} + +// IsValid reports whether the message is valid. +// +// An invalid message is an empty, read-only value. +// +// An invalid message often corresponds to a nil pointer of the concrete +// message type, but the details are implementation dependent. +// Validity is not part of the protobuf data model, and may not +// be preserved in marshaling or other operations. +func (x *fastReflection_MsgUpdateParamsResponse) IsValid() bool { + return x != nil +} + +// ProtoMethods returns optional fastReflectionFeature-path implementations of various operations. +// This method may return nil. +// +// The returned methods type is identical to +// "google.golang.org/protobuf/runtime/protoiface".Methods. +// Consult the protoiface package documentation for details. +func (x *fastReflection_MsgUpdateParamsResponse) ProtoMethods() *protoiface.Methods { + size := func(input protoiface.SizeInput) protoiface.SizeOutput { + x := input.Message.Interface().(*MsgUpdateParamsResponse) + if x == nil { + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: 0, + } + } + options := runtime.SizeInputToOptions(input) + _ = options + var n int + var l int + _ = l + if x.unknownFields != nil { + n += len(x.unknownFields) + } + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: n, + } + } + + marshal := func(input protoiface.MarshalInput) (protoiface.MarshalOutput, error) { + x := input.Message.Interface().(*MsgUpdateParamsResponse) + if x == nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + options := runtime.MarshalInputToOptions(input) + _ = options + size := options.Size(x) + dAtA := make([]byte, size) + i := len(dAtA) + _ = i + var l int + _ = l + if x.unknownFields != nil { + i -= len(x.unknownFields) + copy(dAtA[i:], x.unknownFields) + } + if input.Buf != nil { + input.Buf = append(input.Buf, dAtA...) + } else { + input.Buf = dAtA + } + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + unmarshal := func(input protoiface.UnmarshalInput) (protoiface.UnmarshalOutput, error) { + x := input.Message.Interface().(*MsgUpdateParamsResponse) + if x == nil { + return protoiface.UnmarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Flags: input.Flags, + }, nil + } + options := runtime.UnmarshalInputToOptions(input) + _ = options + dAtA := input.Buf + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: MsgUpdateParamsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: MsgUpdateParamsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := runtime.Skip(dAtA[iNdEx:]) + if err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if !options.DiscardUnknown { + x.unknownFields = append(x.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + } + iNdEx += skippy + } + } + + if iNdEx > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, nil + } + return &protoiface.Methods{ + NoUnkeyedLiterals: struct{}{}, + Flags: protoiface.SupportMarshalDeterministic | protoiface.SupportUnmarshalDiscardUnknown, + Size: size, + Marshal: marshal, + Unmarshal: unmarshal, + Merge: nil, + CheckInitialized: nil, + } +} + +var ( + md_MsgVoteReadResult protoreflect.MessageDescriptor + fd_MsgVoteReadResult_signer protoreflect.FieldDescriptor + fd_MsgVoteReadResult_request_id protoreflect.FieldDescriptor + fd_MsgVoteReadResult_result protoreflect.FieldDescriptor +) + +func init() { + file_ucallback_v1_tx_proto_init() + md_MsgVoteReadResult = File_ucallback_v1_tx_proto.Messages().ByName("MsgVoteReadResult") + fd_MsgVoteReadResult_signer = md_MsgVoteReadResult.Fields().ByName("signer") + fd_MsgVoteReadResult_request_id = md_MsgVoteReadResult.Fields().ByName("request_id") + fd_MsgVoteReadResult_result = md_MsgVoteReadResult.Fields().ByName("result") +} + +var _ protoreflect.Message = (*fastReflection_MsgVoteReadResult)(nil) + +type fastReflection_MsgVoteReadResult MsgVoteReadResult + +func (x *MsgVoteReadResult) ProtoReflect() protoreflect.Message { + return (*fastReflection_MsgVoteReadResult)(x) +} + +func (x *MsgVoteReadResult) slowProtoReflect() protoreflect.Message { + mi := &file_ucallback_v1_tx_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +var _fastReflection_MsgVoteReadResult_messageType fastReflection_MsgVoteReadResult_messageType +var _ protoreflect.MessageType = fastReflection_MsgVoteReadResult_messageType{} + +type fastReflection_MsgVoteReadResult_messageType struct{} + +func (x fastReflection_MsgVoteReadResult_messageType) Zero() protoreflect.Message { + return (*fastReflection_MsgVoteReadResult)(nil) +} +func (x fastReflection_MsgVoteReadResult_messageType) New() protoreflect.Message { + return new(fastReflection_MsgVoteReadResult) +} +func (x fastReflection_MsgVoteReadResult_messageType) Descriptor() protoreflect.MessageDescriptor { + return md_MsgVoteReadResult +} + +// Descriptor returns message descriptor, which contains only the protobuf +// type information for the message. +func (x *fastReflection_MsgVoteReadResult) Descriptor() protoreflect.MessageDescriptor { + return md_MsgVoteReadResult +} + +// Type returns the message type, which encapsulates both Go and protobuf +// type information. If the Go type information is not needed, +// it is recommended that the message descriptor be used instead. +func (x *fastReflection_MsgVoteReadResult) Type() protoreflect.MessageType { + return _fastReflection_MsgVoteReadResult_messageType +} + +// New returns a newly allocated and mutable empty message. +func (x *fastReflection_MsgVoteReadResult) New() protoreflect.Message { + return new(fastReflection_MsgVoteReadResult) +} + +// Interface unwraps the message reflection interface and +// returns the underlying ProtoMessage interface. +func (x *fastReflection_MsgVoteReadResult) Interface() protoreflect.ProtoMessage { + return (*MsgVoteReadResult)(x) +} + +// Range iterates over every populated field in an undefined order, +// calling f for each field descriptor and value encountered. +// Range returns immediately if f returns false. +// While iterating, mutating operations may only be performed +// on the current field descriptor. +func (x *fastReflection_MsgVoteReadResult) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { + if x.Signer != "" { + value := protoreflect.ValueOfString(x.Signer) + if !f(fd_MsgVoteReadResult_signer, value) { + return + } + } + if x.RequestId != "" { + value := protoreflect.ValueOfString(x.RequestId) + if !f(fd_MsgVoteReadResult_request_id, value) { + return + } + } + if x.Result != nil { + value := protoreflect.ValueOfMessage(x.Result.ProtoReflect()) + if !f(fd_MsgVoteReadResult_result, value) { + return + } + } +} + +// Has reports whether a field is populated. +// +// Some fields have the property of nullability where it is possible to +// distinguish between the default value of a field and whether the field +// was explicitly populated with the default value. Singular message fields, +// member fields of a oneof, and proto2 scalar fields are nullable. Such +// fields are populated only if explicitly set. +// +// In other cases (aside from the nullable cases above), +// a proto3 scalar field is populated if it contains a non-zero value, and +// a repeated field is populated if it is non-empty. +func (x *fastReflection_MsgVoteReadResult) Has(fd protoreflect.FieldDescriptor) bool { + switch fd.FullName() { + case "ucallback.v1.MsgVoteReadResult.signer": + return x.Signer != "" + case "ucallback.v1.MsgVoteReadResult.request_id": + return x.RequestId != "" + case "ucallback.v1.MsgVoteReadResult.result": + return x.Result != nil + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.MsgVoteReadResult")) + } + panic(fmt.Errorf("message ucallback.v1.MsgVoteReadResult does not contain field %s", fd.FullName())) + } +} + +// Clear clears the field such that a subsequent Has call reports false. +// +// Clearing an extension field clears both the extension type and value +// associated with the given field number. +// +// Clear is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_MsgVoteReadResult) Clear(fd protoreflect.FieldDescriptor) { + switch fd.FullName() { + case "ucallback.v1.MsgVoteReadResult.signer": + x.Signer = "" + case "ucallback.v1.MsgVoteReadResult.request_id": + x.RequestId = "" + case "ucallback.v1.MsgVoteReadResult.result": + x.Result = nil + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.MsgVoteReadResult")) + } + panic(fmt.Errorf("message ucallback.v1.MsgVoteReadResult does not contain field %s", fd.FullName())) + } +} + +// Get retrieves the value for a field. +// +// For unpopulated scalars, it returns the default value, where +// the default value of a bytes scalar is guaranteed to be a copy. +// For unpopulated composite types, it returns an empty, read-only view +// of the value; to obtain a mutable reference, use Mutable. +func (x *fastReflection_MsgVoteReadResult) Get(descriptor protoreflect.FieldDescriptor) protoreflect.Value { + switch descriptor.FullName() { + case "ucallback.v1.MsgVoteReadResult.signer": + value := x.Signer + return protoreflect.ValueOfString(value) + case "ucallback.v1.MsgVoteReadResult.request_id": + value := x.RequestId + return protoreflect.ValueOfString(value) + case "ucallback.v1.MsgVoteReadResult.result": + value := x.Result + return protoreflect.ValueOfMessage(value.ProtoReflect()) + default: + if descriptor.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.MsgVoteReadResult")) + } + panic(fmt.Errorf("message ucallback.v1.MsgVoteReadResult does not contain field %s", descriptor.FullName())) + } +} + +// Set stores the value for a field. +// +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType. +// When setting a composite type, it is unspecified whether the stored value +// aliases the source's memory in any way. If the composite value is an +// empty, read-only value, then it panics. +// +// Set is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_MsgVoteReadResult) Set(fd protoreflect.FieldDescriptor, value protoreflect.Value) { + switch fd.FullName() { + case "ucallback.v1.MsgVoteReadResult.signer": + x.Signer = value.Interface().(string) + case "ucallback.v1.MsgVoteReadResult.request_id": + x.RequestId = value.Interface().(string) + case "ucallback.v1.MsgVoteReadResult.result": + x.Result = value.Message().Interface().(*ReadResult) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.MsgVoteReadResult")) + } + panic(fmt.Errorf("message ucallback.v1.MsgVoteReadResult does not contain field %s", fd.FullName())) + } +} + +// Mutable returns a mutable reference to a composite type. +// +// If the field is unpopulated, it may allocate a composite value. +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType +// if not already stored. +// It panics if the field does not contain a composite type. +// +// Mutable is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_MsgVoteReadResult) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "ucallback.v1.MsgVoteReadResult.result": + if x.Result == nil { + x.Result = new(ReadResult) + } + return protoreflect.ValueOfMessage(x.Result.ProtoReflect()) + case "ucallback.v1.MsgVoteReadResult.signer": + panic(fmt.Errorf("field signer of message ucallback.v1.MsgVoteReadResult is not mutable")) + case "ucallback.v1.MsgVoteReadResult.request_id": + panic(fmt.Errorf("field request_id of message ucallback.v1.MsgVoteReadResult is not mutable")) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.MsgVoteReadResult")) + } + panic(fmt.Errorf("message ucallback.v1.MsgVoteReadResult does not contain field %s", fd.FullName())) + } +} + +// NewField returns a new value that is assignable to the field +// for the given descriptor. For scalars, this returns the default value. +// For lists, maps, and messages, this returns a new, empty, mutable value. +func (x *fastReflection_MsgVoteReadResult) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "ucallback.v1.MsgVoteReadResult.signer": + return protoreflect.ValueOfString("") + case "ucallback.v1.MsgVoteReadResult.request_id": + return protoreflect.ValueOfString("") + case "ucallback.v1.MsgVoteReadResult.result": + m := new(ReadResult) + return protoreflect.ValueOfMessage(m.ProtoReflect()) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.MsgVoteReadResult")) + } + panic(fmt.Errorf("message ucallback.v1.MsgVoteReadResult does not contain field %s", fd.FullName())) + } +} + +// WhichOneof reports which field within the oneof is populated, +// returning nil if none are populated. +// It panics if the oneof descriptor does not belong to this message. +func (x *fastReflection_MsgVoteReadResult) WhichOneof(d protoreflect.OneofDescriptor) protoreflect.FieldDescriptor { + switch d.FullName() { + default: + panic(fmt.Errorf("%s is not a oneof field in ucallback.v1.MsgVoteReadResult", d.FullName())) + } + panic("unreachable") +} + +// GetUnknown retrieves the entire list of unknown fields. +// The caller may only mutate the contents of the RawFields +// if the mutated bytes are stored back into the message with SetUnknown. +func (x *fastReflection_MsgVoteReadResult) GetUnknown() protoreflect.RawFields { + return x.unknownFields +} + +// SetUnknown stores an entire list of unknown fields. +// The raw fields must be syntactically valid according to the wire format. +// An implementation may panic if this is not the case. +// Once stored, the caller must not mutate the content of the RawFields. +// An empty RawFields may be passed to clear the fields. +// +// SetUnknown is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_MsgVoteReadResult) SetUnknown(fields protoreflect.RawFields) { + x.unknownFields = fields +} + +// IsValid reports whether the message is valid. +// +// An invalid message is an empty, read-only value. +// +// An invalid message often corresponds to a nil pointer of the concrete +// message type, but the details are implementation dependent. +// Validity is not part of the protobuf data model, and may not +// be preserved in marshaling or other operations. +func (x *fastReflection_MsgVoteReadResult) IsValid() bool { + return x != nil +} + +// ProtoMethods returns optional fastReflectionFeature-path implementations of various operations. +// This method may return nil. +// +// The returned methods type is identical to +// "google.golang.org/protobuf/runtime/protoiface".Methods. +// Consult the protoiface package documentation for details. +func (x *fastReflection_MsgVoteReadResult) ProtoMethods() *protoiface.Methods { + size := func(input protoiface.SizeInput) protoiface.SizeOutput { + x := input.Message.Interface().(*MsgVoteReadResult) + if x == nil { + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: 0, + } + } + options := runtime.SizeInputToOptions(input) + _ = options + var n int + var l int + _ = l + l = len(x.Signer) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } + l = len(x.RequestId) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } + if x.Result != nil { + l = options.Size(x.Result) + n += 1 + l + runtime.Sov(uint64(l)) + } + if x.unknownFields != nil { + n += len(x.unknownFields) + } + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: n, + } + } + + marshal := func(input protoiface.MarshalInput) (protoiface.MarshalOutput, error) { + x := input.Message.Interface().(*MsgVoteReadResult) + if x == nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + options := runtime.MarshalInputToOptions(input) + _ = options + size := options.Size(x) + dAtA := make([]byte, size) + i := len(dAtA) + _ = i + var l int + _ = l + if x.unknownFields != nil { + i -= len(x.unknownFields) + copy(dAtA[i:], x.unknownFields) + } + if x.Result != nil { + encoded, err := options.Marshal(x.Result) + if err != nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, err + } + i -= len(encoded) + copy(dAtA[i:], encoded) + i = runtime.EncodeVarint(dAtA, i, uint64(len(encoded))) + i-- + dAtA[i] = 0x1a + } + if len(x.RequestId) > 0 { + i -= len(x.RequestId) + copy(dAtA[i:], x.RequestId) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.RequestId))) + i-- + dAtA[i] = 0x12 + } + if len(x.Signer) > 0 { + i -= len(x.Signer) + copy(dAtA[i:], x.Signer) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.Signer))) + i-- + dAtA[i] = 0xa + } + if input.Buf != nil { + input.Buf = append(input.Buf, dAtA...) + } else { + input.Buf = dAtA + } + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + unmarshal := func(input protoiface.UnmarshalInput) (protoiface.UnmarshalOutput, error) { + x := input.Message.Interface().(*MsgVoteReadResult) + if x == nil { + return protoiface.UnmarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Flags: input.Flags, + }, nil + } + options := runtime.UnmarshalInputToOptions(input) + _ = options + dAtA := input.Buf + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: MsgVoteReadResult: wiretype end group for non-group") + } + if fieldNum <= 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: MsgVoteReadResult: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Signer", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.Signer = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field RequestId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.RequestId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Result", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if x.Result == nil { + x.Result = &ReadResult{} + } + if err := options.Unmarshal(dAtA[iNdEx:postIndex], x.Result); err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := runtime.Skip(dAtA[iNdEx:]) + if err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if !options.DiscardUnknown { + x.unknownFields = append(x.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + } + iNdEx += skippy + } + } + + if iNdEx > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, nil + } + return &protoiface.Methods{ + NoUnkeyedLiterals: struct{}{}, + Flags: protoiface.SupportMarshalDeterministic | protoiface.SupportUnmarshalDiscardUnknown, + Size: size, + Marshal: marshal, + Unmarshal: unmarshal, + Merge: nil, + CheckInitialized: nil, + } +} + +var ( + md_MsgVoteReadResultResponse protoreflect.MessageDescriptor + fd_MsgVoteReadResultResponse_finalized protoreflect.FieldDescriptor +) + +func init() { + file_ucallback_v1_tx_proto_init() + md_MsgVoteReadResultResponse = File_ucallback_v1_tx_proto.Messages().ByName("MsgVoteReadResultResponse") + fd_MsgVoteReadResultResponse_finalized = md_MsgVoteReadResultResponse.Fields().ByName("finalized") +} + +var _ protoreflect.Message = (*fastReflection_MsgVoteReadResultResponse)(nil) + +type fastReflection_MsgVoteReadResultResponse MsgVoteReadResultResponse + +func (x *MsgVoteReadResultResponse) ProtoReflect() protoreflect.Message { + return (*fastReflection_MsgVoteReadResultResponse)(x) +} + +func (x *MsgVoteReadResultResponse) slowProtoReflect() protoreflect.Message { + mi := &file_ucallback_v1_tx_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +var _fastReflection_MsgVoteReadResultResponse_messageType fastReflection_MsgVoteReadResultResponse_messageType +var _ protoreflect.MessageType = fastReflection_MsgVoteReadResultResponse_messageType{} + +type fastReflection_MsgVoteReadResultResponse_messageType struct{} + +func (x fastReflection_MsgVoteReadResultResponse_messageType) Zero() protoreflect.Message { + return (*fastReflection_MsgVoteReadResultResponse)(nil) +} +func (x fastReflection_MsgVoteReadResultResponse_messageType) New() protoreflect.Message { + return new(fastReflection_MsgVoteReadResultResponse) +} +func (x fastReflection_MsgVoteReadResultResponse_messageType) Descriptor() protoreflect.MessageDescriptor { + return md_MsgVoteReadResultResponse +} + +// Descriptor returns message descriptor, which contains only the protobuf +// type information for the message. +func (x *fastReflection_MsgVoteReadResultResponse) Descriptor() protoreflect.MessageDescriptor { + return md_MsgVoteReadResultResponse +} + +// Type returns the message type, which encapsulates both Go and protobuf +// type information. If the Go type information is not needed, +// it is recommended that the message descriptor be used instead. +func (x *fastReflection_MsgVoteReadResultResponse) Type() protoreflect.MessageType { + return _fastReflection_MsgVoteReadResultResponse_messageType +} + +// New returns a newly allocated and mutable empty message. +func (x *fastReflection_MsgVoteReadResultResponse) New() protoreflect.Message { + return new(fastReflection_MsgVoteReadResultResponse) +} + +// Interface unwraps the message reflection interface and +// returns the underlying ProtoMessage interface. +func (x *fastReflection_MsgVoteReadResultResponse) Interface() protoreflect.ProtoMessage { + return (*MsgVoteReadResultResponse)(x) +} + +// Range iterates over every populated field in an undefined order, +// calling f for each field descriptor and value encountered. +// Range returns immediately if f returns false. +// While iterating, mutating operations may only be performed +// on the current field descriptor. +func (x *fastReflection_MsgVoteReadResultResponse) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { + if x.Finalized != false { + value := protoreflect.ValueOfBool(x.Finalized) + if !f(fd_MsgVoteReadResultResponse_finalized, value) { + return + } + } +} + +// Has reports whether a field is populated. +// +// Some fields have the property of nullability where it is possible to +// distinguish between the default value of a field and whether the field +// was explicitly populated with the default value. Singular message fields, +// member fields of a oneof, and proto2 scalar fields are nullable. Such +// fields are populated only if explicitly set. +// +// In other cases (aside from the nullable cases above), +// a proto3 scalar field is populated if it contains a non-zero value, and +// a repeated field is populated if it is non-empty. +func (x *fastReflection_MsgVoteReadResultResponse) Has(fd protoreflect.FieldDescriptor) bool { + switch fd.FullName() { + case "ucallback.v1.MsgVoteReadResultResponse.finalized": + return x.Finalized != false + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.MsgVoteReadResultResponse")) + } + panic(fmt.Errorf("message ucallback.v1.MsgVoteReadResultResponse does not contain field %s", fd.FullName())) + } +} + +// Clear clears the field such that a subsequent Has call reports false. +// +// Clearing an extension field clears both the extension type and value +// associated with the given field number. +// +// Clear is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_MsgVoteReadResultResponse) Clear(fd protoreflect.FieldDescriptor) { + switch fd.FullName() { + case "ucallback.v1.MsgVoteReadResultResponse.finalized": + x.Finalized = false + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.MsgVoteReadResultResponse")) + } + panic(fmt.Errorf("message ucallback.v1.MsgVoteReadResultResponse does not contain field %s", fd.FullName())) + } +} + +// Get retrieves the value for a field. +// +// For unpopulated scalars, it returns the default value, where +// the default value of a bytes scalar is guaranteed to be a copy. +// For unpopulated composite types, it returns an empty, read-only view +// of the value; to obtain a mutable reference, use Mutable. +func (x *fastReflection_MsgVoteReadResultResponse) Get(descriptor protoreflect.FieldDescriptor) protoreflect.Value { + switch descriptor.FullName() { + case "ucallback.v1.MsgVoteReadResultResponse.finalized": + value := x.Finalized + return protoreflect.ValueOfBool(value) + default: + if descriptor.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.MsgVoteReadResultResponse")) + } + panic(fmt.Errorf("message ucallback.v1.MsgVoteReadResultResponse does not contain field %s", descriptor.FullName())) + } +} + +// Set stores the value for a field. +// +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType. +// When setting a composite type, it is unspecified whether the stored value +// aliases the source's memory in any way. If the composite value is an +// empty, read-only value, then it panics. +// +// Set is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_MsgVoteReadResultResponse) Set(fd protoreflect.FieldDescriptor, value protoreflect.Value) { + switch fd.FullName() { + case "ucallback.v1.MsgVoteReadResultResponse.finalized": + x.Finalized = value.Bool() + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.MsgVoteReadResultResponse")) + } + panic(fmt.Errorf("message ucallback.v1.MsgVoteReadResultResponse does not contain field %s", fd.FullName())) + } +} + +// Mutable returns a mutable reference to a composite type. +// +// If the field is unpopulated, it may allocate a composite value. +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType +// if not already stored. +// It panics if the field does not contain a composite type. +// +// Mutable is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_MsgVoteReadResultResponse) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "ucallback.v1.MsgVoteReadResultResponse.finalized": + panic(fmt.Errorf("field finalized of message ucallback.v1.MsgVoteReadResultResponse is not mutable")) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.MsgVoteReadResultResponse")) + } + panic(fmt.Errorf("message ucallback.v1.MsgVoteReadResultResponse does not contain field %s", fd.FullName())) + } +} + +// NewField returns a new value that is assignable to the field +// for the given descriptor. For scalars, this returns the default value. +// For lists, maps, and messages, this returns a new, empty, mutable value. +func (x *fastReflection_MsgVoteReadResultResponse) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "ucallback.v1.MsgVoteReadResultResponse.finalized": + return protoreflect.ValueOfBool(false) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.MsgVoteReadResultResponse")) + } + panic(fmt.Errorf("message ucallback.v1.MsgVoteReadResultResponse does not contain field %s", fd.FullName())) + } +} + +// WhichOneof reports which field within the oneof is populated, +// returning nil if none are populated. +// It panics if the oneof descriptor does not belong to this message. +func (x *fastReflection_MsgVoteReadResultResponse) WhichOneof(d protoreflect.OneofDescriptor) protoreflect.FieldDescriptor { + switch d.FullName() { + default: + panic(fmt.Errorf("%s is not a oneof field in ucallback.v1.MsgVoteReadResultResponse", d.FullName())) + } + panic("unreachable") +} + +// GetUnknown retrieves the entire list of unknown fields. +// The caller may only mutate the contents of the RawFields +// if the mutated bytes are stored back into the message with SetUnknown. +func (x *fastReflection_MsgVoteReadResultResponse) GetUnknown() protoreflect.RawFields { + return x.unknownFields +} + +// SetUnknown stores an entire list of unknown fields. +// The raw fields must be syntactically valid according to the wire format. +// An implementation may panic if this is not the case. +// Once stored, the caller must not mutate the content of the RawFields. +// An empty RawFields may be passed to clear the fields. +// +// SetUnknown is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_MsgVoteReadResultResponse) SetUnknown(fields protoreflect.RawFields) { + x.unknownFields = fields +} + +// IsValid reports whether the message is valid. +// +// An invalid message is an empty, read-only value. +// +// An invalid message often corresponds to a nil pointer of the concrete +// message type, but the details are implementation dependent. +// Validity is not part of the protobuf data model, and may not +// be preserved in marshaling or other operations. +func (x *fastReflection_MsgVoteReadResultResponse) IsValid() bool { + return x != nil +} + +// ProtoMethods returns optional fastReflectionFeature-path implementations of various operations. +// This method may return nil. +// +// The returned methods type is identical to +// "google.golang.org/protobuf/runtime/protoiface".Methods. +// Consult the protoiface package documentation for details. +func (x *fastReflection_MsgVoteReadResultResponse) ProtoMethods() *protoiface.Methods { + size := func(input protoiface.SizeInput) protoiface.SizeOutput { + x := input.Message.Interface().(*MsgVoteReadResultResponse) + if x == nil { + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: 0, + } + } + options := runtime.SizeInputToOptions(input) + _ = options + var n int + var l int + _ = l + if x.Finalized { + n += 2 + } + if x.unknownFields != nil { + n += len(x.unknownFields) + } + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: n, + } + } + + marshal := func(input protoiface.MarshalInput) (protoiface.MarshalOutput, error) { + x := input.Message.Interface().(*MsgVoteReadResultResponse) + if x == nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + options := runtime.MarshalInputToOptions(input) + _ = options + size := options.Size(x) + dAtA := make([]byte, size) + i := len(dAtA) + _ = i + var l int + _ = l + if x.unknownFields != nil { + i -= len(x.unknownFields) + copy(dAtA[i:], x.unknownFields) + } + if x.Finalized { + i-- + if x.Finalized { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x8 + } + if input.Buf != nil { + input.Buf = append(input.Buf, dAtA...) + } else { + input.Buf = dAtA + } + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + unmarshal := func(input protoiface.UnmarshalInput) (protoiface.UnmarshalOutput, error) { + x := input.Message.Interface().(*MsgVoteReadResultResponse) + if x == nil { + return protoiface.UnmarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Flags: input.Flags, + }, nil + } + options := runtime.UnmarshalInputToOptions(input) + _ = options + dAtA := input.Buf + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: MsgVoteReadResultResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: MsgVoteReadResultResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Finalized", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + x.Finalized = bool(v != 0) + default: + iNdEx = preIndex + skippy, err := runtime.Skip(dAtA[iNdEx:]) + if err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if !options.DiscardUnknown { + x.unknownFields = append(x.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + } + iNdEx += skippy + } + } + + if iNdEx > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, nil + } + return &protoiface.Methods{ + NoUnkeyedLiterals: struct{}{}, + Flags: protoiface.SupportMarshalDeterministic | protoiface.SupportUnmarshalDiscardUnknown, + Size: size, + Marshal: marshal, + Unmarshal: unmarshal, + Merge: nil, + CheckInitialized: nil, + } +} + +var ( + md_MsgRetryReadExpiry protoreflect.MessageDescriptor + fd_MsgRetryReadExpiry_signer protoreflect.FieldDescriptor + fd_MsgRetryReadExpiry_request_id protoreflect.FieldDescriptor +) + +func init() { + file_ucallback_v1_tx_proto_init() + md_MsgRetryReadExpiry = File_ucallback_v1_tx_proto.Messages().ByName("MsgRetryReadExpiry") + fd_MsgRetryReadExpiry_signer = md_MsgRetryReadExpiry.Fields().ByName("signer") + fd_MsgRetryReadExpiry_request_id = md_MsgRetryReadExpiry.Fields().ByName("request_id") +} + +var _ protoreflect.Message = (*fastReflection_MsgRetryReadExpiry)(nil) + +type fastReflection_MsgRetryReadExpiry MsgRetryReadExpiry + +func (x *MsgRetryReadExpiry) ProtoReflect() protoreflect.Message { + return (*fastReflection_MsgRetryReadExpiry)(x) +} + +func (x *MsgRetryReadExpiry) slowProtoReflect() protoreflect.Message { + mi := &file_ucallback_v1_tx_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +var _fastReflection_MsgRetryReadExpiry_messageType fastReflection_MsgRetryReadExpiry_messageType +var _ protoreflect.MessageType = fastReflection_MsgRetryReadExpiry_messageType{} + +type fastReflection_MsgRetryReadExpiry_messageType struct{} + +func (x fastReflection_MsgRetryReadExpiry_messageType) Zero() protoreflect.Message { + return (*fastReflection_MsgRetryReadExpiry)(nil) +} +func (x fastReflection_MsgRetryReadExpiry_messageType) New() protoreflect.Message { + return new(fastReflection_MsgRetryReadExpiry) +} +func (x fastReflection_MsgRetryReadExpiry_messageType) Descriptor() protoreflect.MessageDescriptor { + return md_MsgRetryReadExpiry +} + +// Descriptor returns message descriptor, which contains only the protobuf +// type information for the message. +func (x *fastReflection_MsgRetryReadExpiry) Descriptor() protoreflect.MessageDescriptor { + return md_MsgRetryReadExpiry +} + +// Type returns the message type, which encapsulates both Go and protobuf +// type information. If the Go type information is not needed, +// it is recommended that the message descriptor be used instead. +func (x *fastReflection_MsgRetryReadExpiry) Type() protoreflect.MessageType { + return _fastReflection_MsgRetryReadExpiry_messageType +} + +// New returns a newly allocated and mutable empty message. +func (x *fastReflection_MsgRetryReadExpiry) New() protoreflect.Message { + return new(fastReflection_MsgRetryReadExpiry) +} + +// Interface unwraps the message reflection interface and +// returns the underlying ProtoMessage interface. +func (x *fastReflection_MsgRetryReadExpiry) Interface() protoreflect.ProtoMessage { + return (*MsgRetryReadExpiry)(x) +} + +// Range iterates over every populated field in an undefined order, +// calling f for each field descriptor and value encountered. +// Range returns immediately if f returns false. +// While iterating, mutating operations may only be performed +// on the current field descriptor. +func (x *fastReflection_MsgRetryReadExpiry) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { + if x.Signer != "" { + value := protoreflect.ValueOfString(x.Signer) + if !f(fd_MsgRetryReadExpiry_signer, value) { + return + } + } + if x.RequestId != "" { + value := protoreflect.ValueOfString(x.RequestId) + if !f(fd_MsgRetryReadExpiry_request_id, value) { + return + } + } +} + +// Has reports whether a field is populated. +// +// Some fields have the property of nullability where it is possible to +// distinguish between the default value of a field and whether the field +// was explicitly populated with the default value. Singular message fields, +// member fields of a oneof, and proto2 scalar fields are nullable. Such +// fields are populated only if explicitly set. +// +// In other cases (aside from the nullable cases above), +// a proto3 scalar field is populated if it contains a non-zero value, and +// a repeated field is populated if it is non-empty. +func (x *fastReflection_MsgRetryReadExpiry) Has(fd protoreflect.FieldDescriptor) bool { + switch fd.FullName() { + case "ucallback.v1.MsgRetryReadExpiry.signer": + return x.Signer != "" + case "ucallback.v1.MsgRetryReadExpiry.request_id": + return x.RequestId != "" + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.MsgRetryReadExpiry")) + } + panic(fmt.Errorf("message ucallback.v1.MsgRetryReadExpiry does not contain field %s", fd.FullName())) + } +} + +// Clear clears the field such that a subsequent Has call reports false. +// +// Clearing an extension field clears both the extension type and value +// associated with the given field number. +// +// Clear is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_MsgRetryReadExpiry) Clear(fd protoreflect.FieldDescriptor) { + switch fd.FullName() { + case "ucallback.v1.MsgRetryReadExpiry.signer": + x.Signer = "" + case "ucallback.v1.MsgRetryReadExpiry.request_id": + x.RequestId = "" + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.MsgRetryReadExpiry")) + } + panic(fmt.Errorf("message ucallback.v1.MsgRetryReadExpiry does not contain field %s", fd.FullName())) + } +} + +// Get retrieves the value for a field. +// +// For unpopulated scalars, it returns the default value, where +// the default value of a bytes scalar is guaranteed to be a copy. +// For unpopulated composite types, it returns an empty, read-only view +// of the value; to obtain a mutable reference, use Mutable. +func (x *fastReflection_MsgRetryReadExpiry) Get(descriptor protoreflect.FieldDescriptor) protoreflect.Value { + switch descriptor.FullName() { + case "ucallback.v1.MsgRetryReadExpiry.signer": + value := x.Signer + return protoreflect.ValueOfString(value) + case "ucallback.v1.MsgRetryReadExpiry.request_id": + value := x.RequestId + return protoreflect.ValueOfString(value) + default: + if descriptor.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.MsgRetryReadExpiry")) + } + panic(fmt.Errorf("message ucallback.v1.MsgRetryReadExpiry does not contain field %s", descriptor.FullName())) + } +} + +// Set stores the value for a field. +// +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType. +// When setting a composite type, it is unspecified whether the stored value +// aliases the source's memory in any way. If the composite value is an +// empty, read-only value, then it panics. +// +// Set is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_MsgRetryReadExpiry) Set(fd protoreflect.FieldDescriptor, value protoreflect.Value) { + switch fd.FullName() { + case "ucallback.v1.MsgRetryReadExpiry.signer": + x.Signer = value.Interface().(string) + case "ucallback.v1.MsgRetryReadExpiry.request_id": + x.RequestId = value.Interface().(string) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.MsgRetryReadExpiry")) + } + panic(fmt.Errorf("message ucallback.v1.MsgRetryReadExpiry does not contain field %s", fd.FullName())) + } +} + +// Mutable returns a mutable reference to a composite type. +// +// If the field is unpopulated, it may allocate a composite value. +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType +// if not already stored. +// It panics if the field does not contain a composite type. +// +// Mutable is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_MsgRetryReadExpiry) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "ucallback.v1.MsgRetryReadExpiry.signer": + panic(fmt.Errorf("field signer of message ucallback.v1.MsgRetryReadExpiry is not mutable")) + case "ucallback.v1.MsgRetryReadExpiry.request_id": + panic(fmt.Errorf("field request_id of message ucallback.v1.MsgRetryReadExpiry is not mutable")) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.MsgRetryReadExpiry")) + } + panic(fmt.Errorf("message ucallback.v1.MsgRetryReadExpiry does not contain field %s", fd.FullName())) + } +} + +// NewField returns a new value that is assignable to the field +// for the given descriptor. For scalars, this returns the default value. +// For lists, maps, and messages, this returns a new, empty, mutable value. +func (x *fastReflection_MsgRetryReadExpiry) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "ucallback.v1.MsgRetryReadExpiry.signer": + return protoreflect.ValueOfString("") + case "ucallback.v1.MsgRetryReadExpiry.request_id": + return protoreflect.ValueOfString("") + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.MsgRetryReadExpiry")) + } + panic(fmt.Errorf("message ucallback.v1.MsgRetryReadExpiry does not contain field %s", fd.FullName())) + } +} + +// WhichOneof reports which field within the oneof is populated, +// returning nil if none are populated. +// It panics if the oneof descriptor does not belong to this message. +func (x *fastReflection_MsgRetryReadExpiry) WhichOneof(d protoreflect.OneofDescriptor) protoreflect.FieldDescriptor { + switch d.FullName() { + default: + panic(fmt.Errorf("%s is not a oneof field in ucallback.v1.MsgRetryReadExpiry", d.FullName())) + } + panic("unreachable") +} + +// GetUnknown retrieves the entire list of unknown fields. +// The caller may only mutate the contents of the RawFields +// if the mutated bytes are stored back into the message with SetUnknown. +func (x *fastReflection_MsgRetryReadExpiry) GetUnknown() protoreflect.RawFields { + return x.unknownFields +} + +// SetUnknown stores an entire list of unknown fields. +// The raw fields must be syntactically valid according to the wire format. +// An implementation may panic if this is not the case. +// Once stored, the caller must not mutate the content of the RawFields. +// An empty RawFields may be passed to clear the fields. +// +// SetUnknown is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_MsgRetryReadExpiry) SetUnknown(fields protoreflect.RawFields) { + x.unknownFields = fields +} + +// IsValid reports whether the message is valid. +// +// An invalid message is an empty, read-only value. +// +// An invalid message often corresponds to a nil pointer of the concrete +// message type, but the details are implementation dependent. +// Validity is not part of the protobuf data model, and may not +// be preserved in marshaling or other operations. +func (x *fastReflection_MsgRetryReadExpiry) IsValid() bool { + return x != nil +} + +// ProtoMethods returns optional fastReflectionFeature-path implementations of various operations. +// This method may return nil. +// +// The returned methods type is identical to +// "google.golang.org/protobuf/runtime/protoiface".Methods. +// Consult the protoiface package documentation for details. +func (x *fastReflection_MsgRetryReadExpiry) ProtoMethods() *protoiface.Methods { + size := func(input protoiface.SizeInput) protoiface.SizeOutput { + x := input.Message.Interface().(*MsgRetryReadExpiry) + if x == nil { + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: 0, + } + } + options := runtime.SizeInputToOptions(input) + _ = options + var n int + var l int + _ = l + l = len(x.Signer) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } + l = len(x.RequestId) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } + if x.unknownFields != nil { + n += len(x.unknownFields) + } + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: n, + } + } + + marshal := func(input protoiface.MarshalInput) (protoiface.MarshalOutput, error) { + x := input.Message.Interface().(*MsgRetryReadExpiry) + if x == nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + options := runtime.MarshalInputToOptions(input) + _ = options + size := options.Size(x) + dAtA := make([]byte, size) + i := len(dAtA) + _ = i + var l int + _ = l + if x.unknownFields != nil { + i -= len(x.unknownFields) + copy(dAtA[i:], x.unknownFields) + } + if len(x.RequestId) > 0 { + i -= len(x.RequestId) + copy(dAtA[i:], x.RequestId) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.RequestId))) + i-- + dAtA[i] = 0x12 + } + if len(x.Signer) > 0 { + i -= len(x.Signer) + copy(dAtA[i:], x.Signer) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.Signer))) + i-- + dAtA[i] = 0xa + } + if input.Buf != nil { + input.Buf = append(input.Buf, dAtA...) + } else { + input.Buf = dAtA + } + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + unmarshal := func(input protoiface.UnmarshalInput) (protoiface.UnmarshalOutput, error) { + x := input.Message.Interface().(*MsgRetryReadExpiry) + if x == nil { + return protoiface.UnmarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Flags: input.Flags, + }, nil + } + options := runtime.UnmarshalInputToOptions(input) + _ = options + dAtA := input.Buf + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: MsgRetryReadExpiry: wiretype end group for non-group") + } + if fieldNum <= 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: MsgRetryReadExpiry: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Signer", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.Signer = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field RequestId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.RequestId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := runtime.Skip(dAtA[iNdEx:]) + if err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if !options.DiscardUnknown { + x.unknownFields = append(x.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + } + iNdEx += skippy + } + } + + if iNdEx > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, nil + } + return &protoiface.Methods{ + NoUnkeyedLiterals: struct{}{}, + Flags: protoiface.SupportMarshalDeterministic | protoiface.SupportUnmarshalDiscardUnknown, + Size: size, + Marshal: marshal, + Unmarshal: unmarshal, + Merge: nil, + CheckInitialized: nil, + } +} + +var ( + md_MsgRetryReadExpiryResponse protoreflect.MessageDescriptor + fd_MsgRetryReadExpiryResponse_settled protoreflect.FieldDescriptor +) + +func init() { + file_ucallback_v1_tx_proto_init() + md_MsgRetryReadExpiryResponse = File_ucallback_v1_tx_proto.Messages().ByName("MsgRetryReadExpiryResponse") + fd_MsgRetryReadExpiryResponse_settled = md_MsgRetryReadExpiryResponse.Fields().ByName("settled") +} + +var _ protoreflect.Message = (*fastReflection_MsgRetryReadExpiryResponse)(nil) + +type fastReflection_MsgRetryReadExpiryResponse MsgRetryReadExpiryResponse + +func (x *MsgRetryReadExpiryResponse) ProtoReflect() protoreflect.Message { + return (*fastReflection_MsgRetryReadExpiryResponse)(x) +} + +func (x *MsgRetryReadExpiryResponse) slowProtoReflect() protoreflect.Message { + mi := &file_ucallback_v1_tx_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +var _fastReflection_MsgRetryReadExpiryResponse_messageType fastReflection_MsgRetryReadExpiryResponse_messageType +var _ protoreflect.MessageType = fastReflection_MsgRetryReadExpiryResponse_messageType{} + +type fastReflection_MsgRetryReadExpiryResponse_messageType struct{} + +func (x fastReflection_MsgRetryReadExpiryResponse_messageType) Zero() protoreflect.Message { + return (*fastReflection_MsgRetryReadExpiryResponse)(nil) +} +func (x fastReflection_MsgRetryReadExpiryResponse_messageType) New() protoreflect.Message { + return new(fastReflection_MsgRetryReadExpiryResponse) +} +func (x fastReflection_MsgRetryReadExpiryResponse_messageType) Descriptor() protoreflect.MessageDescriptor { + return md_MsgRetryReadExpiryResponse +} + +// Descriptor returns message descriptor, which contains only the protobuf +// type information for the message. +func (x *fastReflection_MsgRetryReadExpiryResponse) Descriptor() protoreflect.MessageDescriptor { + return md_MsgRetryReadExpiryResponse +} + +// Type returns the message type, which encapsulates both Go and protobuf +// type information. If the Go type information is not needed, +// it is recommended that the message descriptor be used instead. +func (x *fastReflection_MsgRetryReadExpiryResponse) Type() protoreflect.MessageType { + return _fastReflection_MsgRetryReadExpiryResponse_messageType +} + +// New returns a newly allocated and mutable empty message. +func (x *fastReflection_MsgRetryReadExpiryResponse) New() protoreflect.Message { + return new(fastReflection_MsgRetryReadExpiryResponse) +} + +// Interface unwraps the message reflection interface and +// returns the underlying ProtoMessage interface. +func (x *fastReflection_MsgRetryReadExpiryResponse) Interface() protoreflect.ProtoMessage { + return (*MsgRetryReadExpiryResponse)(x) +} + +// Range iterates over every populated field in an undefined order, +// calling f for each field descriptor and value encountered. +// Range returns immediately if f returns false. +// While iterating, mutating operations may only be performed +// on the current field descriptor. +func (x *fastReflection_MsgRetryReadExpiryResponse) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { + if x.Settled != false { + value := protoreflect.ValueOfBool(x.Settled) + if !f(fd_MsgRetryReadExpiryResponse_settled, value) { + return + } + } +} + +// Has reports whether a field is populated. +// +// Some fields have the property of nullability where it is possible to +// distinguish between the default value of a field and whether the field +// was explicitly populated with the default value. Singular message fields, +// member fields of a oneof, and proto2 scalar fields are nullable. Such +// fields are populated only if explicitly set. +// +// In other cases (aside from the nullable cases above), +// a proto3 scalar field is populated if it contains a non-zero value, and +// a repeated field is populated if it is non-empty. +func (x *fastReflection_MsgRetryReadExpiryResponse) Has(fd protoreflect.FieldDescriptor) bool { + switch fd.FullName() { + case "ucallback.v1.MsgRetryReadExpiryResponse.settled": + return x.Settled != false + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.MsgRetryReadExpiryResponse")) + } + panic(fmt.Errorf("message ucallback.v1.MsgRetryReadExpiryResponse does not contain field %s", fd.FullName())) + } +} + +// Clear clears the field such that a subsequent Has call reports false. +// +// Clearing an extension field clears both the extension type and value +// associated with the given field number. +// +// Clear is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_MsgRetryReadExpiryResponse) Clear(fd protoreflect.FieldDescriptor) { + switch fd.FullName() { + case "ucallback.v1.MsgRetryReadExpiryResponse.settled": + x.Settled = false + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.MsgRetryReadExpiryResponse")) + } + panic(fmt.Errorf("message ucallback.v1.MsgRetryReadExpiryResponse does not contain field %s", fd.FullName())) + } +} + +// Get retrieves the value for a field. +// +// For unpopulated scalars, it returns the default value, where +// the default value of a bytes scalar is guaranteed to be a copy. +// For unpopulated composite types, it returns an empty, read-only view +// of the value; to obtain a mutable reference, use Mutable. +func (x *fastReflection_MsgRetryReadExpiryResponse) Get(descriptor protoreflect.FieldDescriptor) protoreflect.Value { + switch descriptor.FullName() { + case "ucallback.v1.MsgRetryReadExpiryResponse.settled": + value := x.Settled + return protoreflect.ValueOfBool(value) + default: + if descriptor.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.MsgRetryReadExpiryResponse")) + } + panic(fmt.Errorf("message ucallback.v1.MsgRetryReadExpiryResponse does not contain field %s", descriptor.FullName())) + } +} + +// Set stores the value for a field. +// +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType. +// When setting a composite type, it is unspecified whether the stored value +// aliases the source's memory in any way. If the composite value is an +// empty, read-only value, then it panics. +// +// Set is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_MsgRetryReadExpiryResponse) Set(fd protoreflect.FieldDescriptor, value protoreflect.Value) { + switch fd.FullName() { + case "ucallback.v1.MsgRetryReadExpiryResponse.settled": + x.Settled = value.Bool() + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.MsgRetryReadExpiryResponse")) + } + panic(fmt.Errorf("message ucallback.v1.MsgRetryReadExpiryResponse does not contain field %s", fd.FullName())) + } +} + +// Mutable returns a mutable reference to a composite type. +// +// If the field is unpopulated, it may allocate a composite value. +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType +// if not already stored. +// It panics if the field does not contain a composite type. +// +// Mutable is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_MsgRetryReadExpiryResponse) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "ucallback.v1.MsgRetryReadExpiryResponse.settled": + panic(fmt.Errorf("field settled of message ucallback.v1.MsgRetryReadExpiryResponse is not mutable")) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.MsgRetryReadExpiryResponse")) + } + panic(fmt.Errorf("message ucallback.v1.MsgRetryReadExpiryResponse does not contain field %s", fd.FullName())) + } +} + +// NewField returns a new value that is assignable to the field +// for the given descriptor. For scalars, this returns the default value. +// For lists, maps, and messages, this returns a new, empty, mutable value. +func (x *fastReflection_MsgRetryReadExpiryResponse) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "ucallback.v1.MsgRetryReadExpiryResponse.settled": + return protoreflect.ValueOfBool(false) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.MsgRetryReadExpiryResponse")) + } + panic(fmt.Errorf("message ucallback.v1.MsgRetryReadExpiryResponse does not contain field %s", fd.FullName())) + } +} + +// WhichOneof reports which field within the oneof is populated, +// returning nil if none are populated. +// It panics if the oneof descriptor does not belong to this message. +func (x *fastReflection_MsgRetryReadExpiryResponse) WhichOneof(d protoreflect.OneofDescriptor) protoreflect.FieldDescriptor { + switch d.FullName() { + default: + panic(fmt.Errorf("%s is not a oneof field in ucallback.v1.MsgRetryReadExpiryResponse", d.FullName())) + } + panic("unreachable") +} + +// GetUnknown retrieves the entire list of unknown fields. +// The caller may only mutate the contents of the RawFields +// if the mutated bytes are stored back into the message with SetUnknown. +func (x *fastReflection_MsgRetryReadExpiryResponse) GetUnknown() protoreflect.RawFields { + return x.unknownFields +} + +// SetUnknown stores an entire list of unknown fields. +// The raw fields must be syntactically valid according to the wire format. +// An implementation may panic if this is not the case. +// Once stored, the caller must not mutate the content of the RawFields. +// An empty RawFields may be passed to clear the fields. +// +// SetUnknown is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_MsgRetryReadExpiryResponse) SetUnknown(fields protoreflect.RawFields) { + x.unknownFields = fields +} + +// IsValid reports whether the message is valid. +// +// An invalid message is an empty, read-only value. +// +// An invalid message often corresponds to a nil pointer of the concrete +// message type, but the details are implementation dependent. +// Validity is not part of the protobuf data model, and may not +// be preserved in marshaling or other operations. +func (x *fastReflection_MsgRetryReadExpiryResponse) IsValid() bool { + return x != nil +} + +// ProtoMethods returns optional fastReflectionFeature-path implementations of various operations. +// This method may return nil. +// +// The returned methods type is identical to +// "google.golang.org/protobuf/runtime/protoiface".Methods. +// Consult the protoiface package documentation for details. +func (x *fastReflection_MsgRetryReadExpiryResponse) ProtoMethods() *protoiface.Methods { + size := func(input protoiface.SizeInput) protoiface.SizeOutput { + x := input.Message.Interface().(*MsgRetryReadExpiryResponse) + if x == nil { + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: 0, + } + } + options := runtime.SizeInputToOptions(input) + _ = options + var n int + var l int + _ = l + if x.Settled { + n += 2 + } + if x.unknownFields != nil { + n += len(x.unknownFields) + } + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: n, + } + } + + marshal := func(input protoiface.MarshalInput) (protoiface.MarshalOutput, error) { + x := input.Message.Interface().(*MsgRetryReadExpiryResponse) + if x == nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + options := runtime.MarshalInputToOptions(input) + _ = options + size := options.Size(x) + dAtA := make([]byte, size) + i := len(dAtA) + _ = i + var l int + _ = l + if x.unknownFields != nil { + i -= len(x.unknownFields) + copy(dAtA[i:], x.unknownFields) + } + if x.Settled { + i-- + if x.Settled { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x8 + } + if input.Buf != nil { + input.Buf = append(input.Buf, dAtA...) + } else { + input.Buf = dAtA + } + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + unmarshal := func(input protoiface.UnmarshalInput) (protoiface.UnmarshalOutput, error) { + x := input.Message.Interface().(*MsgRetryReadExpiryResponse) + if x == nil { + return protoiface.UnmarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Flags: input.Flags, + }, nil + } + options := runtime.UnmarshalInputToOptions(input) + _ = options + dAtA := input.Buf + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: MsgRetryReadExpiryResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: MsgRetryReadExpiryResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Settled", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + x.Settled = bool(v != 0) + default: + iNdEx = preIndex + skippy, err := runtime.Skip(dAtA[iNdEx:]) + if err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if !options.DiscardUnknown { + x.unknownFields = append(x.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + } + iNdEx += skippy + } + } + + if iNdEx > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, nil + } + return &protoiface.Methods{ + NoUnkeyedLiterals: struct{}{}, + Flags: protoiface.SupportMarshalDeterministic | protoiface.SupportUnmarshalDiscardUnknown, + Size: size, + Marshal: marshal, + Unmarshal: unmarshal, + Merge: nil, + CheckInitialized: nil, + } +} + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.27.0 +// protoc (unknown) +// source: ucallback/v1/tx.proto + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// MsgUpdateParams is the Msg/UpdateParams request type. +// +// Since: cosmos-sdk 0.47 +type MsgUpdateParams struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // authority is the address of the governance account. + Authority string `protobuf:"bytes,1,opt,name=authority,proto3" json:"authority,omitempty"` + // params defines the parameters to update. + // + // NOTE: All parameters must be supplied. + Params *Params `protobuf:"bytes,2,opt,name=params,proto3" json:"params,omitempty"` +} + +func (x *MsgUpdateParams) Reset() { + *x = MsgUpdateParams{} + if protoimpl.UnsafeEnabled { + mi := &file_ucallback_v1_tx_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MsgUpdateParams) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MsgUpdateParams) ProtoMessage() {} + +// Deprecated: Use MsgUpdateParams.ProtoReflect.Descriptor instead. +func (*MsgUpdateParams) Descriptor() ([]byte, []int) { + return file_ucallback_v1_tx_proto_rawDescGZIP(), []int{0} +} + +func (x *MsgUpdateParams) GetAuthority() string { + if x != nil { + return x.Authority + } + return "" +} + +func (x *MsgUpdateParams) GetParams() *Params { + if x != nil { + return x.Params + } + return nil +} + +// MsgUpdateParamsResponse defines the response structure for executing a +// MsgUpdateParams message. +// +// Since: cosmos-sdk 0.47 +type MsgUpdateParamsResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *MsgUpdateParamsResponse) Reset() { + *x = MsgUpdateParamsResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_ucallback_v1_tx_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MsgUpdateParamsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MsgUpdateParamsResponse) ProtoMessage() {} + +// Deprecated: Use MsgUpdateParamsResponse.ProtoReflect.Descriptor instead. +func (*MsgUpdateParamsResponse) Descriptor() ([]byte, []int) { + return file_ucallback_v1_tx_proto_rawDescGZIP(), []int{1} +} + +// MsgVoteReadResult is broadcast by a universal validator that has executed a +// read request against the destination chain. +// +// The ballot the vote lands on is derived from (request_id, result), so two +// validators reporting the same observation converge on one ballot and any +// disagreement produces a distinct ballot that never reaches quorum. Nothing +// validator-local may appear in `result` for that reason — notably there is no +// error message field. +type MsgVoteReadResult struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // signer is the Cosmos address of the voting universal validator. + Signer string `protobuf:"bytes,1,opt,name=signer,proto3" json:"signer,omitempty"` + // request_id identifies the read request being voted on. + RequestId string `protobuf:"bytes,2,opt,name=request_id,json=requestId,proto3" json:"request_id,omitempty"` + // result is the observation. Every field participates in the ballot key. + Result *ReadResult `protobuf:"bytes,3,opt,name=result,proto3" json:"result,omitempty"` +} + +func (x *MsgVoteReadResult) Reset() { + *x = MsgVoteReadResult{} + if protoimpl.UnsafeEnabled { + mi := &file_ucallback_v1_tx_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MsgVoteReadResult) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MsgVoteReadResult) ProtoMessage() {} + +// Deprecated: Use MsgVoteReadResult.ProtoReflect.Descriptor instead. +func (*MsgVoteReadResult) Descriptor() ([]byte, []int) { + return file_ucallback_v1_tx_proto_rawDescGZIP(), []int{2} +} + +func (x *MsgVoteReadResult) GetSigner() string { + if x != nil { + return x.Signer + } + return "" +} + +func (x *MsgVoteReadResult) GetRequestId() string { + if x != nil { + return x.RequestId + } + return "" +} + +func (x *MsgVoteReadResult) GetResult() *ReadResult { + if x != nil { + return x.Result + } + return nil +} + +type MsgVoteReadResultResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // finalized reports whether this vote carried the ballot to quorum. + Finalized bool `protobuf:"varint,1,opt,name=finalized,proto3" json:"finalized,omitempty"` +} + +func (x *MsgVoteReadResultResponse) Reset() { + *x = MsgVoteReadResultResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_ucallback_v1_tx_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MsgVoteReadResultResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MsgVoteReadResultResponse) ProtoMessage() {} + +// Deprecated: Use MsgVoteReadResultResponse.ProtoReflect.Descriptor instead. +func (*MsgVoteReadResultResponse) Descriptor() ([]byte, []int) { + return file_ucallback_v1_tx_proto_rawDescGZIP(), []int{3} +} + +func (x *MsgVoteReadResultResponse) GetFinalized() bool { + if x != nil { + return x.Finalized + } + return false +} + +// MsgRetryReadExpiry is an admin escape hatch. For a read left ABORTED after +// MaxExpiryAttempts, this makes one more attempt at expireExternalRead. +// +// Needed because ABORTED is a dead end that nothing else can leave. The contract +// may still hold the request as pending with the funder's refund uncredited, and +// expireExternalRead is module-gated — no user, relayer or admin can call it +// directly. The sweeper will not retry either: ABORTED is terminal, so the record +// is out of PendingByExpiry. +// +// Each message is worth exactly one attempt: the attempt count is the record's own +// PCTx history, which is already at the limit, so a failure returns it to ABORTED +// with the new reason rather than granting a fresh budget. +type MsgRetryReadExpiry struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // signer must equal uvalidator Params.Admin + Signer string `protobuf:"bytes,1,opt,name=signer,proto3" json:"signer,omitempty"` + // request_id of the abandoned read. + RequestId string `protobuf:"bytes,2,opt,name=request_id,json=requestId,proto3" json:"request_id,omitempty"` +} + +func (x *MsgRetryReadExpiry) Reset() { + *x = MsgRetryReadExpiry{} + if protoimpl.UnsafeEnabled { + mi := &file_ucallback_v1_tx_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MsgRetryReadExpiry) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MsgRetryReadExpiry) ProtoMessage() {} + +// Deprecated: Use MsgRetryReadExpiry.ProtoReflect.Descriptor instead. +func (*MsgRetryReadExpiry) Descriptor() ([]byte, []int) { + return file_ucallback_v1_tx_proto_rawDescGZIP(), []int{4} +} + +func (x *MsgRetryReadExpiry) GetSigner() string { + if x != nil { + return x.Signer + } + return "" +} + +func (x *MsgRetryReadExpiry) GetRequestId() string { + if x != nil { + return x.RequestId + } + return "" +} + +type MsgRetryReadExpiryResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // settled reports whether the contract accepted the expiry this time. + Settled bool `protobuf:"varint,1,opt,name=settled,proto3" json:"settled,omitempty"` +} + +func (x *MsgRetryReadExpiryResponse) Reset() { + *x = MsgRetryReadExpiryResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_ucallback_v1_tx_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MsgRetryReadExpiryResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MsgRetryReadExpiryResponse) ProtoMessage() {} + +// Deprecated: Use MsgRetryReadExpiryResponse.ProtoReflect.Descriptor instead. +func (*MsgRetryReadExpiryResponse) Descriptor() ([]byte, []int) { + return file_ucallback_v1_tx_proto_rawDescGZIP(), []int{5} +} + +func (x *MsgRetryReadExpiryResponse) GetSettled() bool { + if x != nil { + return x.Settled + } + return false +} + +var File_ucallback_v1_tx_proto protoreflect.FileDescriptor + +var file_ucallback_v1_tx_proto_rawDesc = []byte{ + 0x0a, 0x15, 0x75, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x2f, 0x76, 0x31, 0x2f, 0x74, + 0x78, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0c, 0x75, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, + 0x63, 0x6b, 0x2e, 0x76, 0x31, 0x1a, 0x17, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x6d, 0x73, + 0x67, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x73, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1a, + 0x75, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x65, 0x6e, + 0x65, 0x73, 0x69, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x18, 0x75, 0x63, 0x61, 0x6c, + 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x14, 0x67, 0x6f, 0x67, 0x6f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, + 0x67, 0x6f, 0x67, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x19, 0x63, 0x6f, 0x73, 0x6d, + 0x6f, 0x73, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x11, 0x61, 0x6d, 0x69, 0x6e, 0x6f, 0x2f, 0x61, 0x6d, 0x69, + 0x6e, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x8d, 0x01, 0x0a, 0x0f, 0x4d, 0x73, 0x67, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x36, 0x0a, 0x09, + 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, + 0x18, 0xd2, 0xb4, 0x2d, 0x14, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x41, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x09, 0x61, 0x75, 0x74, 0x68, 0x6f, + 0x72, 0x69, 0x74, 0x79, 0x12, 0x32, 0x0a, 0x06, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x75, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, + 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x42, 0x04, 0xc8, 0xde, 0x1f, 0x00, + 0x52, 0x06, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x3a, 0x0e, 0x82, 0xe7, 0xb0, 0x2a, 0x09, 0x61, + 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x22, 0x19, 0x0a, 0x17, 0x4d, 0x73, 0x67, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0xc3, 0x01, 0x0a, 0x11, 0x4d, 0x73, 0x67, 0x56, 0x6f, 0x74, 0x65, 0x52, + 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x30, 0x0a, 0x06, 0x73, 0x69, 0x67, + 0x6e, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x18, 0xd2, 0xb4, 0x2d, 0x14, 0x63, + 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x53, 0x74, 0x72, + 0x69, 0x6e, 0x67, 0x52, 0x06, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x12, 0x1d, 0x0a, 0x0a, 0x72, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x30, 0x0a, 0x06, 0x72, 0x65, + 0x73, 0x75, 0x6c, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x75, 0x63, 0x61, + 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, + 0x73, 0x75, 0x6c, 0x74, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x3a, 0x2b, 0x82, 0xe7, + 0xb0, 0x2a, 0x06, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x8a, 0xe7, 0xb0, 0x2a, 0x1b, 0x75, 0x63, + 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x2f, 0x4d, 0x73, 0x67, 0x56, 0x6f, 0x74, 0x65, 0x52, + 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x39, 0x0a, 0x19, 0x4d, 0x73, 0x67, + 0x56, 0x6f, 0x74, 0x65, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x69, + 0x7a, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x66, 0x69, 0x6e, 0x61, 0x6c, + 0x69, 0x7a, 0x65, 0x64, 0x22, 0x93, 0x01, 0x0a, 0x12, 0x4d, 0x73, 0x67, 0x52, 0x65, 0x74, 0x72, + 0x79, 0x52, 0x65, 0x61, 0x64, 0x45, 0x78, 0x70, 0x69, 0x72, 0x79, 0x12, 0x30, 0x0a, 0x06, 0x73, + 0x69, 0x67, 0x6e, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x18, 0xd2, 0xb4, 0x2d, + 0x14, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x53, + 0x74, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x06, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x12, 0x1d, 0x0a, + 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x3a, 0x2c, 0x82, 0xe7, + 0xb0, 0x2a, 0x06, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x8a, 0xe7, 0xb0, 0x2a, 0x1c, 0x75, 0x63, + 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x2f, 0x4d, 0x73, 0x67, 0x52, 0x65, 0x74, 0x72, 0x79, + 0x52, 0x65, 0x61, 0x64, 0x45, 0x78, 0x70, 0x69, 0x72, 0x79, 0x22, 0x36, 0x0a, 0x1a, 0x4d, 0x73, + 0x67, 0x52, 0x65, 0x74, 0x72, 0x79, 0x52, 0x65, 0x61, 0x64, 0x45, 0x78, 0x70, 0x69, 0x72, 0x79, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x65, 0x74, 0x74, + 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, 0x65, 0x74, 0x74, 0x6c, + 0x65, 0x64, 0x32, 0x9d, 0x02, 0x0a, 0x03, 0x4d, 0x73, 0x67, 0x12, 0x5a, 0x0a, 0x0e, 0x56, 0x6f, + 0x74, 0x65, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x1f, 0x2e, 0x75, + 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x73, 0x67, 0x56, + 0x6f, 0x74, 0x65, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x1a, 0x27, 0x2e, + 0x75, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x73, 0x67, + 0x56, 0x6f, 0x74, 0x65, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5d, 0x0a, 0x0f, 0x52, 0x65, 0x74, 0x72, 0x79, 0x52, + 0x65, 0x61, 0x64, 0x45, 0x78, 0x70, 0x69, 0x72, 0x79, 0x12, 0x20, 0x2e, 0x75, 0x63, 0x61, 0x6c, + 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x73, 0x67, 0x52, 0x65, 0x74, 0x72, + 0x79, 0x52, 0x65, 0x61, 0x64, 0x45, 0x78, 0x70, 0x69, 0x72, 0x79, 0x1a, 0x28, 0x2e, 0x75, 0x63, + 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x73, 0x67, 0x52, 0x65, + 0x74, 0x72, 0x79, 0x52, 0x65, 0x61, 0x64, 0x45, 0x78, 0x70, 0x69, 0x72, 0x79, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x54, 0x0a, 0x0c, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, + 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x1d, 0x2e, 0x75, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, + 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x73, 0x67, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x61, + 0x72, 0x61, 0x6d, 0x73, 0x1a, 0x25, 0x2e, 0x75, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, + 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x73, 0x67, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x61, 0x72, + 0x61, 0x6d, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x1a, 0x05, 0x80, 0xe7, 0xb0, + 0x2a, 0x01, 0x42, 0xaf, 0x01, 0x0a, 0x10, 0x63, 0x6f, 0x6d, 0x2e, 0x75, 0x63, 0x61, 0x6c, 0x6c, + 0x62, 0x61, 0x63, 0x6b, 0x2e, 0x76, 0x31, 0x42, 0x07, 0x54, 0x78, 0x50, 0x72, 0x6f, 0x74, 0x6f, + 0x50, 0x01, 0x5a, 0x41, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, + 0x75, 0x73, 0x68, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x2f, 0x70, 0x75, 0x73, 0x68, 0x2d, 0x63, 0x68, + 0x61, 0x69, 0x6e, 0x2d, 0x6e, 0x6f, 0x64, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x75, 0x63, 0x61, + 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x2f, 0x76, 0x31, 0x3b, 0x75, 0x63, 0x61, 0x6c, 0x6c, 0x62, + 0x61, 0x63, 0x6b, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x55, 0x58, 0x58, 0xaa, 0x02, 0x0c, 0x55, 0x63, + 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x0c, 0x55, 0x63, 0x61, + 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x18, 0x55, 0x63, 0x61, 0x6c, + 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0d, 0x55, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, + 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_ucallback_v1_tx_proto_rawDescOnce sync.Once + file_ucallback_v1_tx_proto_rawDescData = file_ucallback_v1_tx_proto_rawDesc +) + +func file_ucallback_v1_tx_proto_rawDescGZIP() []byte { + file_ucallback_v1_tx_proto_rawDescOnce.Do(func() { + file_ucallback_v1_tx_proto_rawDescData = protoimpl.X.CompressGZIP(file_ucallback_v1_tx_proto_rawDescData) + }) + return file_ucallback_v1_tx_proto_rawDescData +} + +var file_ucallback_v1_tx_proto_msgTypes = make([]protoimpl.MessageInfo, 6) +var file_ucallback_v1_tx_proto_goTypes = []interface{}{ + (*MsgUpdateParams)(nil), // 0: ucallback.v1.MsgUpdateParams + (*MsgUpdateParamsResponse)(nil), // 1: ucallback.v1.MsgUpdateParamsResponse + (*MsgVoteReadResult)(nil), // 2: ucallback.v1.MsgVoteReadResult + (*MsgVoteReadResultResponse)(nil), // 3: ucallback.v1.MsgVoteReadResultResponse + (*MsgRetryReadExpiry)(nil), // 4: ucallback.v1.MsgRetryReadExpiry + (*MsgRetryReadExpiryResponse)(nil), // 5: ucallback.v1.MsgRetryReadExpiryResponse + (*Params)(nil), // 6: ucallback.v1.Params + (*ReadResult)(nil), // 7: ucallback.v1.ReadResult +} +var file_ucallback_v1_tx_proto_depIdxs = []int32{ + 6, // 0: ucallback.v1.MsgUpdateParams.params:type_name -> ucallback.v1.Params + 7, // 1: ucallback.v1.MsgVoteReadResult.result:type_name -> ucallback.v1.ReadResult + 2, // 2: ucallback.v1.Msg.VoteReadResult:input_type -> ucallback.v1.MsgVoteReadResult + 4, // 3: ucallback.v1.Msg.RetryReadExpiry:input_type -> ucallback.v1.MsgRetryReadExpiry + 0, // 4: ucallback.v1.Msg.UpdateParams:input_type -> ucallback.v1.MsgUpdateParams + 3, // 5: ucallback.v1.Msg.VoteReadResult:output_type -> ucallback.v1.MsgVoteReadResultResponse + 5, // 6: ucallback.v1.Msg.RetryReadExpiry:output_type -> ucallback.v1.MsgRetryReadExpiryResponse + 1, // 7: ucallback.v1.Msg.UpdateParams:output_type -> ucallback.v1.MsgUpdateParamsResponse + 5, // [5:8] is the sub-list for method output_type + 2, // [2:5] is the sub-list for method input_type + 2, // [2:2] is the sub-list for extension type_name + 2, // [2:2] is the sub-list for extension extendee + 0, // [0:2] is the sub-list for field type_name +} + +func init() { file_ucallback_v1_tx_proto_init() } +func file_ucallback_v1_tx_proto_init() { + if File_ucallback_v1_tx_proto != nil { + return + } + file_ucallback_v1_genesis_proto_init() + file_ucallback_v1_types_proto_init() + if !protoimpl.UnsafeEnabled { + file_ucallback_v1_tx_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MsgUpdateParams); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ucallback_v1_tx_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MsgUpdateParamsResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ucallback_v1_tx_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MsgVoteReadResult); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ucallback_v1_tx_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MsgVoteReadResultResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ucallback_v1_tx_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MsgRetryReadExpiry); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ucallback_v1_tx_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MsgRetryReadExpiryResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_ucallback_v1_tx_proto_rawDesc, + NumEnums: 0, + NumMessages: 6, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_ucallback_v1_tx_proto_goTypes, + DependencyIndexes: file_ucallback_v1_tx_proto_depIdxs, + MessageInfos: file_ucallback_v1_tx_proto_msgTypes, + }.Build() + File_ucallback_v1_tx_proto = out.File + file_ucallback_v1_tx_proto_rawDesc = nil + file_ucallback_v1_tx_proto_goTypes = nil + file_ucallback_v1_tx_proto_depIdxs = nil +} diff --git a/api/ucallback/v1/tx_grpc.pb.go b/api/ucallback/v1/tx_grpc.pb.go new file mode 100644 index 00000000..52b68c23 --- /dev/null +++ b/api/ucallback/v1/tx_grpc.pb.go @@ -0,0 +1,195 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.3.0 +// - protoc (unknown) +// source: ucallback/v1/tx.proto + +package ucallbackv1 + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.32.0 or later. +const _ = grpc.SupportPackageIsVersion7 + +const ( + Msg_VoteReadResult_FullMethodName = "/ucallback.v1.Msg/VoteReadResult" + Msg_RetryReadExpiry_FullMethodName = "/ucallback.v1.Msg/RetryReadExpiry" + Msg_UpdateParams_FullMethodName = "/ucallback.v1.Msg/UpdateParams" +) + +// MsgClient is the client API for Msg service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type MsgClient interface { + // VoteReadResult submits one universal validator's observation of a read + // request's outcome on the destination chain. + VoteReadResult(ctx context.Context, in *MsgVoteReadResult, opts ...grpc.CallOption) (*MsgVoteReadResultResponse, error) + // RetryReadExpiry reopens the expiry of a read the chain abandoned. + RetryReadExpiry(ctx context.Context, in *MsgRetryReadExpiry, opts ...grpc.CallOption) (*MsgRetryReadExpiryResponse, error) + // UpdateParams defines a governance operation for updating the parameters. + // + // Since: cosmos-sdk 0.47 + UpdateParams(ctx context.Context, in *MsgUpdateParams, opts ...grpc.CallOption) (*MsgUpdateParamsResponse, error) +} + +type msgClient struct { + cc grpc.ClientConnInterface +} + +func NewMsgClient(cc grpc.ClientConnInterface) MsgClient { + return &msgClient{cc} +} + +func (c *msgClient) VoteReadResult(ctx context.Context, in *MsgVoteReadResult, opts ...grpc.CallOption) (*MsgVoteReadResultResponse, error) { + out := new(MsgVoteReadResultResponse) + err := c.cc.Invoke(ctx, Msg_VoteReadResult_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) RetryReadExpiry(ctx context.Context, in *MsgRetryReadExpiry, opts ...grpc.CallOption) (*MsgRetryReadExpiryResponse, error) { + out := new(MsgRetryReadExpiryResponse) + err := c.cc.Invoke(ctx, Msg_RetryReadExpiry_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) UpdateParams(ctx context.Context, in *MsgUpdateParams, opts ...grpc.CallOption) (*MsgUpdateParamsResponse, error) { + out := new(MsgUpdateParamsResponse) + err := c.cc.Invoke(ctx, Msg_UpdateParams_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// MsgServer is the server API for Msg service. +// All implementations must embed UnimplementedMsgServer +// for forward compatibility +type MsgServer interface { + // VoteReadResult submits one universal validator's observation of a read + // request's outcome on the destination chain. + VoteReadResult(context.Context, *MsgVoteReadResult) (*MsgVoteReadResultResponse, error) + // RetryReadExpiry reopens the expiry of a read the chain abandoned. + RetryReadExpiry(context.Context, *MsgRetryReadExpiry) (*MsgRetryReadExpiryResponse, error) + // UpdateParams defines a governance operation for updating the parameters. + // + // Since: cosmos-sdk 0.47 + UpdateParams(context.Context, *MsgUpdateParams) (*MsgUpdateParamsResponse, error) + mustEmbedUnimplementedMsgServer() +} + +// UnimplementedMsgServer must be embedded to have forward compatible implementations. +type UnimplementedMsgServer struct { +} + +func (UnimplementedMsgServer) VoteReadResult(context.Context, *MsgVoteReadResult) (*MsgVoteReadResultResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method VoteReadResult not implemented") +} +func (UnimplementedMsgServer) RetryReadExpiry(context.Context, *MsgRetryReadExpiry) (*MsgRetryReadExpiryResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method RetryReadExpiry not implemented") +} +func (UnimplementedMsgServer) UpdateParams(context.Context, *MsgUpdateParams) (*MsgUpdateParamsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateParams not implemented") +} +func (UnimplementedMsgServer) mustEmbedUnimplementedMsgServer() {} + +// UnsafeMsgServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to MsgServer will +// result in compilation errors. +type UnsafeMsgServer interface { + mustEmbedUnimplementedMsgServer() +} + +func RegisterMsgServer(s grpc.ServiceRegistrar, srv MsgServer) { + s.RegisterService(&Msg_ServiceDesc, srv) +} + +func _Msg_VoteReadResult_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgVoteReadResult) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).VoteReadResult(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Msg_VoteReadResult_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).VoteReadResult(ctx, req.(*MsgVoteReadResult)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_RetryReadExpiry_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgRetryReadExpiry) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).RetryReadExpiry(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Msg_RetryReadExpiry_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).RetryReadExpiry(ctx, req.(*MsgRetryReadExpiry)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_UpdateParams_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgUpdateParams) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).UpdateParams(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Msg_UpdateParams_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).UpdateParams(ctx, req.(*MsgUpdateParams)) + } + return interceptor(ctx, in, info, handler) +} + +// Msg_ServiceDesc is the grpc.ServiceDesc for Msg service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var Msg_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "ucallback.v1.Msg", + HandlerType: (*MsgServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "VoteReadResult", + Handler: _Msg_VoteReadResult_Handler, + }, + { + MethodName: "RetryReadExpiry", + Handler: _Msg_RetryReadExpiry_Handler, + }, + { + MethodName: "UpdateParams", + Handler: _Msg_UpdateParams_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "ucallback/v1/tx.proto", +} diff --git a/api/ucallback/v1/types.pulsar.go b/api/ucallback/v1/types.pulsar.go new file mode 100644 index 00000000..1c7e0fa0 --- /dev/null +++ b/api/ucallback/v1/types.pulsar.go @@ -0,0 +1,4451 @@ +// Code generated by protoc-gen-go-pulsar. DO NOT EDIT. +package ucallbackv1 + +import ( + _ "cosmossdk.io/api/amino" + fmt "fmt" + runtime "github.com/cosmos/cosmos-proto/runtime" + _ "github.com/cosmos/gogoproto/gogoproto" + v1 "github.com/pushchain/push-chain-node/api/uexecutor/v1" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoiface "google.golang.org/protobuf/runtime/protoiface" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" +) + +var ( + md_ReadRequest protoreflect.MessageDescriptor + fd_ReadRequest_request_id protoreflect.FieldDescriptor + fd_ReadRequest_destination_chain protoreflect.FieldDescriptor + fd_ReadRequest_owner protoreflect.FieldDescriptor + fd_ReadRequest_query protoreflect.FieldDescriptor + fd_ReadRequest_min_confirmations protoreflect.FieldDescriptor + fd_ReadRequest_destination_block_height protoreflect.FieldDescriptor + fd_ReadRequest_expiry_block_height protoreflect.FieldDescriptor + fd_ReadRequest_created_at_height protoreflect.FieldDescriptor + fd_ReadRequest_callback_target protoreflect.FieldDescriptor + fd_ReadRequest_original_funder protoreflect.FieldDescriptor + fd_ReadRequest_fees_deposited protoreflect.FieldDescriptor + fd_ReadRequest_max_fee protoreflect.FieldDescriptor + fd_ReadRequest_requested_tx_hash protoreflect.FieldDescriptor + fd_ReadRequest_requested_log_index protoreflect.FieldDescriptor + fd_ReadRequest_protocol_fee protoreflect.FieldDescriptor + fd_ReadRequest_callback_budget protoreflect.FieldDescriptor + fd_ReadRequest_callback_gas_limit protoreflect.FieldDescriptor + fd_ReadRequest_revert_recipient protoreflect.FieldDescriptor +) + +func init() { + file_ucallback_v1_types_proto_init() + md_ReadRequest = File_ucallback_v1_types_proto.Messages().ByName("ReadRequest") + fd_ReadRequest_request_id = md_ReadRequest.Fields().ByName("request_id") + fd_ReadRequest_destination_chain = md_ReadRequest.Fields().ByName("destination_chain") + fd_ReadRequest_owner = md_ReadRequest.Fields().ByName("owner") + fd_ReadRequest_query = md_ReadRequest.Fields().ByName("query") + fd_ReadRequest_min_confirmations = md_ReadRequest.Fields().ByName("min_confirmations") + fd_ReadRequest_destination_block_height = md_ReadRequest.Fields().ByName("destination_block_height") + fd_ReadRequest_expiry_block_height = md_ReadRequest.Fields().ByName("expiry_block_height") + fd_ReadRequest_created_at_height = md_ReadRequest.Fields().ByName("created_at_height") + fd_ReadRequest_callback_target = md_ReadRequest.Fields().ByName("callback_target") + fd_ReadRequest_original_funder = md_ReadRequest.Fields().ByName("original_funder") + fd_ReadRequest_fees_deposited = md_ReadRequest.Fields().ByName("fees_deposited") + fd_ReadRequest_max_fee = md_ReadRequest.Fields().ByName("max_fee") + fd_ReadRequest_requested_tx_hash = md_ReadRequest.Fields().ByName("requested_tx_hash") + fd_ReadRequest_requested_log_index = md_ReadRequest.Fields().ByName("requested_log_index") + fd_ReadRequest_protocol_fee = md_ReadRequest.Fields().ByName("protocol_fee") + fd_ReadRequest_callback_budget = md_ReadRequest.Fields().ByName("callback_budget") + fd_ReadRequest_callback_gas_limit = md_ReadRequest.Fields().ByName("callback_gas_limit") + fd_ReadRequest_revert_recipient = md_ReadRequest.Fields().ByName("revert_recipient") +} + +var _ protoreflect.Message = (*fastReflection_ReadRequest)(nil) + +type fastReflection_ReadRequest ReadRequest + +func (x *ReadRequest) ProtoReflect() protoreflect.Message { + return (*fastReflection_ReadRequest)(x) +} + +func (x *ReadRequest) slowProtoReflect() protoreflect.Message { + mi := &file_ucallback_v1_types_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +var _fastReflection_ReadRequest_messageType fastReflection_ReadRequest_messageType +var _ protoreflect.MessageType = fastReflection_ReadRequest_messageType{} + +type fastReflection_ReadRequest_messageType struct{} + +func (x fastReflection_ReadRequest_messageType) Zero() protoreflect.Message { + return (*fastReflection_ReadRequest)(nil) +} +func (x fastReflection_ReadRequest_messageType) New() protoreflect.Message { + return new(fastReflection_ReadRequest) +} +func (x fastReflection_ReadRequest_messageType) Descriptor() protoreflect.MessageDescriptor { + return md_ReadRequest +} + +// Descriptor returns message descriptor, which contains only the protobuf +// type information for the message. +func (x *fastReflection_ReadRequest) Descriptor() protoreflect.MessageDescriptor { + return md_ReadRequest +} + +// Type returns the message type, which encapsulates both Go and protobuf +// type information. If the Go type information is not needed, +// it is recommended that the message descriptor be used instead. +func (x *fastReflection_ReadRequest) Type() protoreflect.MessageType { + return _fastReflection_ReadRequest_messageType +} + +// New returns a newly allocated and mutable empty message. +func (x *fastReflection_ReadRequest) New() protoreflect.Message { + return new(fastReflection_ReadRequest) +} + +// Interface unwraps the message reflection interface and +// returns the underlying ProtoMessage interface. +func (x *fastReflection_ReadRequest) Interface() protoreflect.ProtoMessage { + return (*ReadRequest)(x) +} + +// Range iterates over every populated field in an undefined order, +// calling f for each field descriptor and value encountered. +// Range returns immediately if f returns false. +// While iterating, mutating operations may only be performed +// on the current field descriptor. +func (x *fastReflection_ReadRequest) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { + if x.RequestId != "" { + value := protoreflect.ValueOfString(x.RequestId) + if !f(fd_ReadRequest_request_id, value) { + return + } + } + if x.DestinationChain != "" { + value := protoreflect.ValueOfString(x.DestinationChain) + if !f(fd_ReadRequest_destination_chain, value) { + return + } + } + if len(x.Owner) != 0 { + value := protoreflect.ValueOfBytes(x.Owner) + if !f(fd_ReadRequest_owner, value) { + return + } + } + if len(x.Query) != 0 { + value := protoreflect.ValueOfBytes(x.Query) + if !f(fd_ReadRequest_query, value) { + return + } + } + if x.MinConfirmations != uint32(0) { + value := protoreflect.ValueOfUint32(x.MinConfirmations) + if !f(fd_ReadRequest_min_confirmations, value) { + return + } + } + if x.DestinationBlockHeight != uint64(0) { + value := protoreflect.ValueOfUint64(x.DestinationBlockHeight) + if !f(fd_ReadRequest_destination_block_height, value) { + return + } + } + if x.ExpiryBlockHeight != uint64(0) { + value := protoreflect.ValueOfUint64(x.ExpiryBlockHeight) + if !f(fd_ReadRequest_expiry_block_height, value) { + return + } + } + if x.CreatedAtHeight != uint64(0) { + value := protoreflect.ValueOfUint64(x.CreatedAtHeight) + if !f(fd_ReadRequest_created_at_height, value) { + return + } + } + if x.CallbackTarget != "" { + value := protoreflect.ValueOfString(x.CallbackTarget) + if !f(fd_ReadRequest_callback_target, value) { + return + } + } + if x.OriginalFunder != "" { + value := protoreflect.ValueOfString(x.OriginalFunder) + if !f(fd_ReadRequest_original_funder, value) { + return + } + } + if x.FeesDeposited != "" { + value := protoreflect.ValueOfString(x.FeesDeposited) + if !f(fd_ReadRequest_fees_deposited, value) { + return + } + } + if x.MaxFee != "" { + value := protoreflect.ValueOfString(x.MaxFee) + if !f(fd_ReadRequest_max_fee, value) { + return + } + } + if x.RequestedTxHash != "" { + value := protoreflect.ValueOfString(x.RequestedTxHash) + if !f(fd_ReadRequest_requested_tx_hash, value) { + return + } + } + if x.RequestedLogIndex != uint64(0) { + value := protoreflect.ValueOfUint64(x.RequestedLogIndex) + if !f(fd_ReadRequest_requested_log_index, value) { + return + } + } + if x.ProtocolFee != "" { + value := protoreflect.ValueOfString(x.ProtocolFee) + if !f(fd_ReadRequest_protocol_fee, value) { + return + } + } + if x.CallbackBudget != "" { + value := protoreflect.ValueOfString(x.CallbackBudget) + if !f(fd_ReadRequest_callback_budget, value) { + return + } + } + if x.CallbackGasLimit != uint64(0) { + value := protoreflect.ValueOfUint64(x.CallbackGasLimit) + if !f(fd_ReadRequest_callback_gas_limit, value) { + return + } + } + if x.RevertRecipient != "" { + value := protoreflect.ValueOfString(x.RevertRecipient) + if !f(fd_ReadRequest_revert_recipient, value) { + return + } + } +} + +// Has reports whether a field is populated. +// +// Some fields have the property of nullability where it is possible to +// distinguish between the default value of a field and whether the field +// was explicitly populated with the default value. Singular message fields, +// member fields of a oneof, and proto2 scalar fields are nullable. Such +// fields are populated only if explicitly set. +// +// In other cases (aside from the nullable cases above), +// a proto3 scalar field is populated if it contains a non-zero value, and +// a repeated field is populated if it is non-empty. +func (x *fastReflection_ReadRequest) Has(fd protoreflect.FieldDescriptor) bool { + switch fd.FullName() { + case "ucallback.v1.ReadRequest.request_id": + return x.RequestId != "" + case "ucallback.v1.ReadRequest.destination_chain": + return x.DestinationChain != "" + case "ucallback.v1.ReadRequest.owner": + return len(x.Owner) != 0 + case "ucallback.v1.ReadRequest.query": + return len(x.Query) != 0 + case "ucallback.v1.ReadRequest.min_confirmations": + return x.MinConfirmations != uint32(0) + case "ucallback.v1.ReadRequest.destination_block_height": + return x.DestinationBlockHeight != uint64(0) + case "ucallback.v1.ReadRequest.expiry_block_height": + return x.ExpiryBlockHeight != uint64(0) + case "ucallback.v1.ReadRequest.created_at_height": + return x.CreatedAtHeight != uint64(0) + case "ucallback.v1.ReadRequest.callback_target": + return x.CallbackTarget != "" + case "ucallback.v1.ReadRequest.original_funder": + return x.OriginalFunder != "" + case "ucallback.v1.ReadRequest.fees_deposited": + return x.FeesDeposited != "" + case "ucallback.v1.ReadRequest.max_fee": + return x.MaxFee != "" + case "ucallback.v1.ReadRequest.requested_tx_hash": + return x.RequestedTxHash != "" + case "ucallback.v1.ReadRequest.requested_log_index": + return x.RequestedLogIndex != uint64(0) + case "ucallback.v1.ReadRequest.protocol_fee": + return x.ProtocolFee != "" + case "ucallback.v1.ReadRequest.callback_budget": + return x.CallbackBudget != "" + case "ucallback.v1.ReadRequest.callback_gas_limit": + return x.CallbackGasLimit != uint64(0) + case "ucallback.v1.ReadRequest.revert_recipient": + return x.RevertRecipient != "" + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.ReadRequest")) + } + panic(fmt.Errorf("message ucallback.v1.ReadRequest does not contain field %s", fd.FullName())) + } +} + +// Clear clears the field such that a subsequent Has call reports false. +// +// Clearing an extension field clears both the extension type and value +// associated with the given field number. +// +// Clear is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_ReadRequest) Clear(fd protoreflect.FieldDescriptor) { + switch fd.FullName() { + case "ucallback.v1.ReadRequest.request_id": + x.RequestId = "" + case "ucallback.v1.ReadRequest.destination_chain": + x.DestinationChain = "" + case "ucallback.v1.ReadRequest.owner": + x.Owner = nil + case "ucallback.v1.ReadRequest.query": + x.Query = nil + case "ucallback.v1.ReadRequest.min_confirmations": + x.MinConfirmations = uint32(0) + case "ucallback.v1.ReadRequest.destination_block_height": + x.DestinationBlockHeight = uint64(0) + case "ucallback.v1.ReadRequest.expiry_block_height": + x.ExpiryBlockHeight = uint64(0) + case "ucallback.v1.ReadRequest.created_at_height": + x.CreatedAtHeight = uint64(0) + case "ucallback.v1.ReadRequest.callback_target": + x.CallbackTarget = "" + case "ucallback.v1.ReadRequest.original_funder": + x.OriginalFunder = "" + case "ucallback.v1.ReadRequest.fees_deposited": + x.FeesDeposited = "" + case "ucallback.v1.ReadRequest.max_fee": + x.MaxFee = "" + case "ucallback.v1.ReadRequest.requested_tx_hash": + x.RequestedTxHash = "" + case "ucallback.v1.ReadRequest.requested_log_index": + x.RequestedLogIndex = uint64(0) + case "ucallback.v1.ReadRequest.protocol_fee": + x.ProtocolFee = "" + case "ucallback.v1.ReadRequest.callback_budget": + x.CallbackBudget = "" + case "ucallback.v1.ReadRequest.callback_gas_limit": + x.CallbackGasLimit = uint64(0) + case "ucallback.v1.ReadRequest.revert_recipient": + x.RevertRecipient = "" + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.ReadRequest")) + } + panic(fmt.Errorf("message ucallback.v1.ReadRequest does not contain field %s", fd.FullName())) + } +} + +// Get retrieves the value for a field. +// +// For unpopulated scalars, it returns the default value, where +// the default value of a bytes scalar is guaranteed to be a copy. +// For unpopulated composite types, it returns an empty, read-only view +// of the value; to obtain a mutable reference, use Mutable. +func (x *fastReflection_ReadRequest) Get(descriptor protoreflect.FieldDescriptor) protoreflect.Value { + switch descriptor.FullName() { + case "ucallback.v1.ReadRequest.request_id": + value := x.RequestId + return protoreflect.ValueOfString(value) + case "ucallback.v1.ReadRequest.destination_chain": + value := x.DestinationChain + return protoreflect.ValueOfString(value) + case "ucallback.v1.ReadRequest.owner": + value := x.Owner + return protoreflect.ValueOfBytes(value) + case "ucallback.v1.ReadRequest.query": + value := x.Query + return protoreflect.ValueOfBytes(value) + case "ucallback.v1.ReadRequest.min_confirmations": + value := x.MinConfirmations + return protoreflect.ValueOfUint32(value) + case "ucallback.v1.ReadRequest.destination_block_height": + value := x.DestinationBlockHeight + return protoreflect.ValueOfUint64(value) + case "ucallback.v1.ReadRequest.expiry_block_height": + value := x.ExpiryBlockHeight + return protoreflect.ValueOfUint64(value) + case "ucallback.v1.ReadRequest.created_at_height": + value := x.CreatedAtHeight + return protoreflect.ValueOfUint64(value) + case "ucallback.v1.ReadRequest.callback_target": + value := x.CallbackTarget + return protoreflect.ValueOfString(value) + case "ucallback.v1.ReadRequest.original_funder": + value := x.OriginalFunder + return protoreflect.ValueOfString(value) + case "ucallback.v1.ReadRequest.fees_deposited": + value := x.FeesDeposited + return protoreflect.ValueOfString(value) + case "ucallback.v1.ReadRequest.max_fee": + value := x.MaxFee + return protoreflect.ValueOfString(value) + case "ucallback.v1.ReadRequest.requested_tx_hash": + value := x.RequestedTxHash + return protoreflect.ValueOfString(value) + case "ucallback.v1.ReadRequest.requested_log_index": + value := x.RequestedLogIndex + return protoreflect.ValueOfUint64(value) + case "ucallback.v1.ReadRequest.protocol_fee": + value := x.ProtocolFee + return protoreflect.ValueOfString(value) + case "ucallback.v1.ReadRequest.callback_budget": + value := x.CallbackBudget + return protoreflect.ValueOfString(value) + case "ucallback.v1.ReadRequest.callback_gas_limit": + value := x.CallbackGasLimit + return protoreflect.ValueOfUint64(value) + case "ucallback.v1.ReadRequest.revert_recipient": + value := x.RevertRecipient + return protoreflect.ValueOfString(value) + default: + if descriptor.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.ReadRequest")) + } + panic(fmt.Errorf("message ucallback.v1.ReadRequest does not contain field %s", descriptor.FullName())) + } +} + +// Set stores the value for a field. +// +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType. +// When setting a composite type, it is unspecified whether the stored value +// aliases the source's memory in any way. If the composite value is an +// empty, read-only value, then it panics. +// +// Set is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_ReadRequest) Set(fd protoreflect.FieldDescriptor, value protoreflect.Value) { + switch fd.FullName() { + case "ucallback.v1.ReadRequest.request_id": + x.RequestId = value.Interface().(string) + case "ucallback.v1.ReadRequest.destination_chain": + x.DestinationChain = value.Interface().(string) + case "ucallback.v1.ReadRequest.owner": + x.Owner = value.Bytes() + case "ucallback.v1.ReadRequest.query": + x.Query = value.Bytes() + case "ucallback.v1.ReadRequest.min_confirmations": + x.MinConfirmations = uint32(value.Uint()) + case "ucallback.v1.ReadRequest.destination_block_height": + x.DestinationBlockHeight = value.Uint() + case "ucallback.v1.ReadRequest.expiry_block_height": + x.ExpiryBlockHeight = value.Uint() + case "ucallback.v1.ReadRequest.created_at_height": + x.CreatedAtHeight = value.Uint() + case "ucallback.v1.ReadRequest.callback_target": + x.CallbackTarget = value.Interface().(string) + case "ucallback.v1.ReadRequest.original_funder": + x.OriginalFunder = value.Interface().(string) + case "ucallback.v1.ReadRequest.fees_deposited": + x.FeesDeposited = value.Interface().(string) + case "ucallback.v1.ReadRequest.max_fee": + x.MaxFee = value.Interface().(string) + case "ucallback.v1.ReadRequest.requested_tx_hash": + x.RequestedTxHash = value.Interface().(string) + case "ucallback.v1.ReadRequest.requested_log_index": + x.RequestedLogIndex = value.Uint() + case "ucallback.v1.ReadRequest.protocol_fee": + x.ProtocolFee = value.Interface().(string) + case "ucallback.v1.ReadRequest.callback_budget": + x.CallbackBudget = value.Interface().(string) + case "ucallback.v1.ReadRequest.callback_gas_limit": + x.CallbackGasLimit = value.Uint() + case "ucallback.v1.ReadRequest.revert_recipient": + x.RevertRecipient = value.Interface().(string) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.ReadRequest")) + } + panic(fmt.Errorf("message ucallback.v1.ReadRequest does not contain field %s", fd.FullName())) + } +} + +// Mutable returns a mutable reference to a composite type. +// +// If the field is unpopulated, it may allocate a composite value. +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType +// if not already stored. +// It panics if the field does not contain a composite type. +// +// Mutable is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_ReadRequest) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "ucallback.v1.ReadRequest.request_id": + panic(fmt.Errorf("field request_id of message ucallback.v1.ReadRequest is not mutable")) + case "ucallback.v1.ReadRequest.destination_chain": + panic(fmt.Errorf("field destination_chain of message ucallback.v1.ReadRequest is not mutable")) + case "ucallback.v1.ReadRequest.owner": + panic(fmt.Errorf("field owner of message ucallback.v1.ReadRequest is not mutable")) + case "ucallback.v1.ReadRequest.query": + panic(fmt.Errorf("field query of message ucallback.v1.ReadRequest is not mutable")) + case "ucallback.v1.ReadRequest.min_confirmations": + panic(fmt.Errorf("field min_confirmations of message ucallback.v1.ReadRequest is not mutable")) + case "ucallback.v1.ReadRequest.destination_block_height": + panic(fmt.Errorf("field destination_block_height of message ucallback.v1.ReadRequest is not mutable")) + case "ucallback.v1.ReadRequest.expiry_block_height": + panic(fmt.Errorf("field expiry_block_height of message ucallback.v1.ReadRequest is not mutable")) + case "ucallback.v1.ReadRequest.created_at_height": + panic(fmt.Errorf("field created_at_height of message ucallback.v1.ReadRequest is not mutable")) + case "ucallback.v1.ReadRequest.callback_target": + panic(fmt.Errorf("field callback_target of message ucallback.v1.ReadRequest is not mutable")) + case "ucallback.v1.ReadRequest.original_funder": + panic(fmt.Errorf("field original_funder of message ucallback.v1.ReadRequest is not mutable")) + case "ucallback.v1.ReadRequest.fees_deposited": + panic(fmt.Errorf("field fees_deposited of message ucallback.v1.ReadRequest is not mutable")) + case "ucallback.v1.ReadRequest.max_fee": + panic(fmt.Errorf("field max_fee of message ucallback.v1.ReadRequest is not mutable")) + case "ucallback.v1.ReadRequest.requested_tx_hash": + panic(fmt.Errorf("field requested_tx_hash of message ucallback.v1.ReadRequest is not mutable")) + case "ucallback.v1.ReadRequest.requested_log_index": + panic(fmt.Errorf("field requested_log_index of message ucallback.v1.ReadRequest is not mutable")) + case "ucallback.v1.ReadRequest.protocol_fee": + panic(fmt.Errorf("field protocol_fee of message ucallback.v1.ReadRequest is not mutable")) + case "ucallback.v1.ReadRequest.callback_budget": + panic(fmt.Errorf("field callback_budget of message ucallback.v1.ReadRequest is not mutable")) + case "ucallback.v1.ReadRequest.callback_gas_limit": + panic(fmt.Errorf("field callback_gas_limit of message ucallback.v1.ReadRequest is not mutable")) + case "ucallback.v1.ReadRequest.revert_recipient": + panic(fmt.Errorf("field revert_recipient of message ucallback.v1.ReadRequest is not mutable")) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.ReadRequest")) + } + panic(fmt.Errorf("message ucallback.v1.ReadRequest does not contain field %s", fd.FullName())) + } +} + +// NewField returns a new value that is assignable to the field +// for the given descriptor. For scalars, this returns the default value. +// For lists, maps, and messages, this returns a new, empty, mutable value. +func (x *fastReflection_ReadRequest) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "ucallback.v1.ReadRequest.request_id": + return protoreflect.ValueOfString("") + case "ucallback.v1.ReadRequest.destination_chain": + return protoreflect.ValueOfString("") + case "ucallback.v1.ReadRequest.owner": + return protoreflect.ValueOfBytes(nil) + case "ucallback.v1.ReadRequest.query": + return protoreflect.ValueOfBytes(nil) + case "ucallback.v1.ReadRequest.min_confirmations": + return protoreflect.ValueOfUint32(uint32(0)) + case "ucallback.v1.ReadRequest.destination_block_height": + return protoreflect.ValueOfUint64(uint64(0)) + case "ucallback.v1.ReadRequest.expiry_block_height": + return protoreflect.ValueOfUint64(uint64(0)) + case "ucallback.v1.ReadRequest.created_at_height": + return protoreflect.ValueOfUint64(uint64(0)) + case "ucallback.v1.ReadRequest.callback_target": + return protoreflect.ValueOfString("") + case "ucallback.v1.ReadRequest.original_funder": + return protoreflect.ValueOfString("") + case "ucallback.v1.ReadRequest.fees_deposited": + return protoreflect.ValueOfString("") + case "ucallback.v1.ReadRequest.max_fee": + return protoreflect.ValueOfString("") + case "ucallback.v1.ReadRequest.requested_tx_hash": + return protoreflect.ValueOfString("") + case "ucallback.v1.ReadRequest.requested_log_index": + return protoreflect.ValueOfUint64(uint64(0)) + case "ucallback.v1.ReadRequest.protocol_fee": + return protoreflect.ValueOfString("") + case "ucallback.v1.ReadRequest.callback_budget": + return protoreflect.ValueOfString("") + case "ucallback.v1.ReadRequest.callback_gas_limit": + return protoreflect.ValueOfUint64(uint64(0)) + case "ucallback.v1.ReadRequest.revert_recipient": + return protoreflect.ValueOfString("") + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.ReadRequest")) + } + panic(fmt.Errorf("message ucallback.v1.ReadRequest does not contain field %s", fd.FullName())) + } +} + +// WhichOneof reports which field within the oneof is populated, +// returning nil if none are populated. +// It panics if the oneof descriptor does not belong to this message. +func (x *fastReflection_ReadRequest) WhichOneof(d protoreflect.OneofDescriptor) protoreflect.FieldDescriptor { + switch d.FullName() { + default: + panic(fmt.Errorf("%s is not a oneof field in ucallback.v1.ReadRequest", d.FullName())) + } + panic("unreachable") +} + +// GetUnknown retrieves the entire list of unknown fields. +// The caller may only mutate the contents of the RawFields +// if the mutated bytes are stored back into the message with SetUnknown. +func (x *fastReflection_ReadRequest) GetUnknown() protoreflect.RawFields { + return x.unknownFields +} + +// SetUnknown stores an entire list of unknown fields. +// The raw fields must be syntactically valid according to the wire format. +// An implementation may panic if this is not the case. +// Once stored, the caller must not mutate the content of the RawFields. +// An empty RawFields may be passed to clear the fields. +// +// SetUnknown is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_ReadRequest) SetUnknown(fields protoreflect.RawFields) { + x.unknownFields = fields +} + +// IsValid reports whether the message is valid. +// +// An invalid message is an empty, read-only value. +// +// An invalid message often corresponds to a nil pointer of the concrete +// message type, but the details are implementation dependent. +// Validity is not part of the protobuf data model, and may not +// be preserved in marshaling or other operations. +func (x *fastReflection_ReadRequest) IsValid() bool { + return x != nil +} + +// ProtoMethods returns optional fastReflectionFeature-path implementations of various operations. +// This method may return nil. +// +// The returned methods type is identical to +// "google.golang.org/protobuf/runtime/protoiface".Methods. +// Consult the protoiface package documentation for details. +func (x *fastReflection_ReadRequest) ProtoMethods() *protoiface.Methods { + size := func(input protoiface.SizeInput) protoiface.SizeOutput { + x := input.Message.Interface().(*ReadRequest) + if x == nil { + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: 0, + } + } + options := runtime.SizeInputToOptions(input) + _ = options + var n int + var l int + _ = l + l = len(x.RequestId) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } + l = len(x.DestinationChain) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } + l = len(x.Owner) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } + l = len(x.Query) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } + if x.MinConfirmations != 0 { + n += 1 + runtime.Sov(uint64(x.MinConfirmations)) + } + if x.DestinationBlockHeight != 0 { + n += 1 + runtime.Sov(uint64(x.DestinationBlockHeight)) + } + if x.ExpiryBlockHeight != 0 { + n += 1 + runtime.Sov(uint64(x.ExpiryBlockHeight)) + } + if x.CreatedAtHeight != 0 { + n += 1 + runtime.Sov(uint64(x.CreatedAtHeight)) + } + l = len(x.CallbackTarget) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } + l = len(x.OriginalFunder) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } + l = len(x.FeesDeposited) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } + l = len(x.MaxFee) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } + l = len(x.RequestedTxHash) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } + if x.RequestedLogIndex != 0 { + n += 1 + runtime.Sov(uint64(x.RequestedLogIndex)) + } + l = len(x.ProtocolFee) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } + l = len(x.CallbackBudget) + if l > 0 { + n += 2 + l + runtime.Sov(uint64(l)) + } + if x.CallbackGasLimit != 0 { + n += 2 + runtime.Sov(uint64(x.CallbackGasLimit)) + } + l = len(x.RevertRecipient) + if l > 0 { + n += 2 + l + runtime.Sov(uint64(l)) + } + if x.unknownFields != nil { + n += len(x.unknownFields) + } + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: n, + } + } + + marshal := func(input protoiface.MarshalInput) (protoiface.MarshalOutput, error) { + x := input.Message.Interface().(*ReadRequest) + if x == nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + options := runtime.MarshalInputToOptions(input) + _ = options + size := options.Size(x) + dAtA := make([]byte, size) + i := len(dAtA) + _ = i + var l int + _ = l + if x.unknownFields != nil { + i -= len(x.unknownFields) + copy(dAtA[i:], x.unknownFields) + } + if len(x.RevertRecipient) > 0 { + i -= len(x.RevertRecipient) + copy(dAtA[i:], x.RevertRecipient) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.RevertRecipient))) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0x92 + } + if x.CallbackGasLimit != 0 { + i = runtime.EncodeVarint(dAtA, i, uint64(x.CallbackGasLimit)) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0x88 + } + if len(x.CallbackBudget) > 0 { + i -= len(x.CallbackBudget) + copy(dAtA[i:], x.CallbackBudget) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.CallbackBudget))) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0x82 + } + if len(x.ProtocolFee) > 0 { + i -= len(x.ProtocolFee) + copy(dAtA[i:], x.ProtocolFee) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.ProtocolFee))) + i-- + dAtA[i] = 0x7a + } + if x.RequestedLogIndex != 0 { + i = runtime.EncodeVarint(dAtA, i, uint64(x.RequestedLogIndex)) + i-- + dAtA[i] = 0x70 + } + if len(x.RequestedTxHash) > 0 { + i -= len(x.RequestedTxHash) + copy(dAtA[i:], x.RequestedTxHash) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.RequestedTxHash))) + i-- + dAtA[i] = 0x6a + } + if len(x.MaxFee) > 0 { + i -= len(x.MaxFee) + copy(dAtA[i:], x.MaxFee) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.MaxFee))) + i-- + dAtA[i] = 0x62 + } + if len(x.FeesDeposited) > 0 { + i -= len(x.FeesDeposited) + copy(dAtA[i:], x.FeesDeposited) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.FeesDeposited))) + i-- + dAtA[i] = 0x5a + } + if len(x.OriginalFunder) > 0 { + i -= len(x.OriginalFunder) + copy(dAtA[i:], x.OriginalFunder) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.OriginalFunder))) + i-- + dAtA[i] = 0x52 + } + if len(x.CallbackTarget) > 0 { + i -= len(x.CallbackTarget) + copy(dAtA[i:], x.CallbackTarget) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.CallbackTarget))) + i-- + dAtA[i] = 0x4a + } + if x.CreatedAtHeight != 0 { + i = runtime.EncodeVarint(dAtA, i, uint64(x.CreatedAtHeight)) + i-- + dAtA[i] = 0x40 + } + if x.ExpiryBlockHeight != 0 { + i = runtime.EncodeVarint(dAtA, i, uint64(x.ExpiryBlockHeight)) + i-- + dAtA[i] = 0x38 + } + if x.DestinationBlockHeight != 0 { + i = runtime.EncodeVarint(dAtA, i, uint64(x.DestinationBlockHeight)) + i-- + dAtA[i] = 0x30 + } + if x.MinConfirmations != 0 { + i = runtime.EncodeVarint(dAtA, i, uint64(x.MinConfirmations)) + i-- + dAtA[i] = 0x28 + } + if len(x.Query) > 0 { + i -= len(x.Query) + copy(dAtA[i:], x.Query) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.Query))) + i-- + dAtA[i] = 0x22 + } + if len(x.Owner) > 0 { + i -= len(x.Owner) + copy(dAtA[i:], x.Owner) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.Owner))) + i-- + dAtA[i] = 0x1a + } + if len(x.DestinationChain) > 0 { + i -= len(x.DestinationChain) + copy(dAtA[i:], x.DestinationChain) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.DestinationChain))) + i-- + dAtA[i] = 0x12 + } + if len(x.RequestId) > 0 { + i -= len(x.RequestId) + copy(dAtA[i:], x.RequestId) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.RequestId))) + i-- + dAtA[i] = 0xa + } + if input.Buf != nil { + input.Buf = append(input.Buf, dAtA...) + } else { + input.Buf = dAtA + } + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + unmarshal := func(input protoiface.UnmarshalInput) (protoiface.UnmarshalOutput, error) { + x := input.Message.Interface().(*ReadRequest) + if x == nil { + return protoiface.UnmarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Flags: input.Flags, + }, nil + } + options := runtime.UnmarshalInputToOptions(input) + _ = options + dAtA := input.Buf + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: ReadRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: ReadRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field RequestId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.RequestId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field DestinationChain", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.DestinationChain = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Owner", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.Owner = append(x.Owner[:0], dAtA[iNdEx:postIndex]...) + if x.Owner == nil { + x.Owner = []byte{} + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Query", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.Query = append(x.Query[:0], dAtA[iNdEx:postIndex]...) + if x.Query == nil { + x.Query = []byte{} + } + iNdEx = postIndex + case 5: + if wireType != 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field MinConfirmations", wireType) + } + x.MinConfirmations = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + x.MinConfirmations |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 6: + if wireType != 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field DestinationBlockHeight", wireType) + } + x.DestinationBlockHeight = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + x.DestinationBlockHeight |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 7: + if wireType != 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field ExpiryBlockHeight", wireType) + } + x.ExpiryBlockHeight = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + x.ExpiryBlockHeight |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 8: + if wireType != 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field CreatedAtHeight", wireType) + } + x.CreatedAtHeight = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + x.CreatedAtHeight |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 9: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field CallbackTarget", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.CallbackTarget = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 10: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field OriginalFunder", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.OriginalFunder = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 11: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field FeesDeposited", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.FeesDeposited = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 12: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field MaxFee", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.MaxFee = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 13: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field RequestedTxHash", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.RequestedTxHash = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 14: + if wireType != 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field RequestedLogIndex", wireType) + } + x.RequestedLogIndex = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + x.RequestedLogIndex |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 15: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field ProtocolFee", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.ProtocolFee = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 16: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field CallbackBudget", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.CallbackBudget = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 17: + if wireType != 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field CallbackGasLimit", wireType) + } + x.CallbackGasLimit = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + x.CallbackGasLimit |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 18: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field RevertRecipient", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.RevertRecipient = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := runtime.Skip(dAtA[iNdEx:]) + if err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if !options.DiscardUnknown { + x.unknownFields = append(x.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + } + iNdEx += skippy + } + } + + if iNdEx > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, nil + } + return &protoiface.Methods{ + NoUnkeyedLiterals: struct{}{}, + Flags: protoiface.SupportMarshalDeterministic | protoiface.SupportUnmarshalDiscardUnknown, + Size: size, + Marshal: marshal, + Unmarshal: unmarshal, + Merge: nil, + CheckInitialized: nil, + } +} + +var _ protoreflect.List = (*_ReadResult_5_list)(nil) + +type _ReadResult_5_list struct { + list *[]*AggregateValue +} + +func (x *_ReadResult_5_list) Len() int { + if x.list == nil { + return 0 + } + return len(*x.list) +} + +func (x *_ReadResult_5_list) Get(i int) protoreflect.Value { + return protoreflect.ValueOfMessage((*x.list)[i].ProtoReflect()) +} + +func (x *_ReadResult_5_list) Set(i int, value protoreflect.Value) { + valueUnwrapped := value.Message() + concreteValue := valueUnwrapped.Interface().(*AggregateValue) + (*x.list)[i] = concreteValue +} + +func (x *_ReadResult_5_list) Append(value protoreflect.Value) { + valueUnwrapped := value.Message() + concreteValue := valueUnwrapped.Interface().(*AggregateValue) + *x.list = append(*x.list, concreteValue) +} + +func (x *_ReadResult_5_list) AppendMutable() protoreflect.Value { + v := new(AggregateValue) + *x.list = append(*x.list, v) + return protoreflect.ValueOfMessage(v.ProtoReflect()) +} + +func (x *_ReadResult_5_list) Truncate(n int) { + for i := n; i < len(*x.list); i++ { + (*x.list)[i] = nil + } + *x.list = (*x.list)[:n] +} + +func (x *_ReadResult_5_list) NewElement() protoreflect.Value { + v := new(AggregateValue) + return protoreflect.ValueOfMessage(v.ProtoReflect()) +} + +func (x *_ReadResult_5_list) IsValid() bool { + return x.list != nil +} + +var ( + md_ReadResult protoreflect.MessageDescriptor + fd_ReadResult_status protoreflect.FieldDescriptor + fd_ReadResult_result_data protoreflect.FieldDescriptor + fd_ReadResult_aggregates protoreflect.FieldDescriptor + fd_ReadResult_error_code protoreflect.FieldDescriptor +) + +func init() { + file_ucallback_v1_types_proto_init() + md_ReadResult = File_ucallback_v1_types_proto.Messages().ByName("ReadResult") + fd_ReadResult_status = md_ReadResult.Fields().ByName("status") + fd_ReadResult_result_data = md_ReadResult.Fields().ByName("result_data") + fd_ReadResult_aggregates = md_ReadResult.Fields().ByName("aggregates") + fd_ReadResult_error_code = md_ReadResult.Fields().ByName("error_code") +} + +var _ protoreflect.Message = (*fastReflection_ReadResult)(nil) + +type fastReflection_ReadResult ReadResult + +func (x *ReadResult) ProtoReflect() protoreflect.Message { + return (*fastReflection_ReadResult)(x) +} + +func (x *ReadResult) slowProtoReflect() protoreflect.Message { + mi := &file_ucallback_v1_types_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +var _fastReflection_ReadResult_messageType fastReflection_ReadResult_messageType +var _ protoreflect.MessageType = fastReflection_ReadResult_messageType{} + +type fastReflection_ReadResult_messageType struct{} + +func (x fastReflection_ReadResult_messageType) Zero() protoreflect.Message { + return (*fastReflection_ReadResult)(nil) +} +func (x fastReflection_ReadResult_messageType) New() protoreflect.Message { + return new(fastReflection_ReadResult) +} +func (x fastReflection_ReadResult_messageType) Descriptor() protoreflect.MessageDescriptor { + return md_ReadResult +} + +// Descriptor returns message descriptor, which contains only the protobuf +// type information for the message. +func (x *fastReflection_ReadResult) Descriptor() protoreflect.MessageDescriptor { + return md_ReadResult +} + +// Type returns the message type, which encapsulates both Go and protobuf +// type information. If the Go type information is not needed, +// it is recommended that the message descriptor be used instead. +func (x *fastReflection_ReadResult) Type() protoreflect.MessageType { + return _fastReflection_ReadResult_messageType +} + +// New returns a newly allocated and mutable empty message. +func (x *fastReflection_ReadResult) New() protoreflect.Message { + return new(fastReflection_ReadResult) +} + +// Interface unwraps the message reflection interface and +// returns the underlying ProtoMessage interface. +func (x *fastReflection_ReadResult) Interface() protoreflect.ProtoMessage { + return (*ReadResult)(x) +} + +// Range iterates over every populated field in an undefined order, +// calling f for each field descriptor and value encountered. +// Range returns immediately if f returns false. +// While iterating, mutating operations may only be performed +// on the current field descriptor. +func (x *fastReflection_ReadResult) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { + if x.Status != 0 { + value := protoreflect.ValueOfEnum((protoreflect.EnumNumber)(x.Status)) + if !f(fd_ReadResult_status, value) { + return + } + } + if len(x.ResultData) != 0 { + value := protoreflect.ValueOfBytes(x.ResultData) + if !f(fd_ReadResult_result_data, value) { + return + } + } + if len(x.Aggregates) != 0 { + value := protoreflect.ValueOfList(&_ReadResult_5_list{list: &x.Aggregates}) + if !f(fd_ReadResult_aggregates, value) { + return + } + } + if x.ErrorCode != 0 { + value := protoreflect.ValueOfEnum((protoreflect.EnumNumber)(x.ErrorCode)) + if !f(fd_ReadResult_error_code, value) { + return + } + } +} + +// Has reports whether a field is populated. +// +// Some fields have the property of nullability where it is possible to +// distinguish between the default value of a field and whether the field +// was explicitly populated with the default value. Singular message fields, +// member fields of a oneof, and proto2 scalar fields are nullable. Such +// fields are populated only if explicitly set. +// +// In other cases (aside from the nullable cases above), +// a proto3 scalar field is populated if it contains a non-zero value, and +// a repeated field is populated if it is non-empty. +func (x *fastReflection_ReadResult) Has(fd protoreflect.FieldDescriptor) bool { + switch fd.FullName() { + case "ucallback.v1.ReadResult.status": + return x.Status != 0 + case "ucallback.v1.ReadResult.result_data": + return len(x.ResultData) != 0 + case "ucallback.v1.ReadResult.aggregates": + return len(x.Aggregates) != 0 + case "ucallback.v1.ReadResult.error_code": + return x.ErrorCode != 0 + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.ReadResult")) + } + panic(fmt.Errorf("message ucallback.v1.ReadResult does not contain field %s", fd.FullName())) + } +} + +// Clear clears the field such that a subsequent Has call reports false. +// +// Clearing an extension field clears both the extension type and value +// associated with the given field number. +// +// Clear is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_ReadResult) Clear(fd protoreflect.FieldDescriptor) { + switch fd.FullName() { + case "ucallback.v1.ReadResult.status": + x.Status = 0 + case "ucallback.v1.ReadResult.result_data": + x.ResultData = nil + case "ucallback.v1.ReadResult.aggregates": + x.Aggregates = nil + case "ucallback.v1.ReadResult.error_code": + x.ErrorCode = 0 + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.ReadResult")) + } + panic(fmt.Errorf("message ucallback.v1.ReadResult does not contain field %s", fd.FullName())) + } +} + +// Get retrieves the value for a field. +// +// For unpopulated scalars, it returns the default value, where +// the default value of a bytes scalar is guaranteed to be a copy. +// For unpopulated composite types, it returns an empty, read-only view +// of the value; to obtain a mutable reference, use Mutable. +func (x *fastReflection_ReadResult) Get(descriptor protoreflect.FieldDescriptor) protoreflect.Value { + switch descriptor.FullName() { + case "ucallback.v1.ReadResult.status": + value := x.Status + return protoreflect.ValueOfEnum((protoreflect.EnumNumber)(value)) + case "ucallback.v1.ReadResult.result_data": + value := x.ResultData + return protoreflect.ValueOfBytes(value) + case "ucallback.v1.ReadResult.aggregates": + if len(x.Aggregates) == 0 { + return protoreflect.ValueOfList(&_ReadResult_5_list{}) + } + listValue := &_ReadResult_5_list{list: &x.Aggregates} + return protoreflect.ValueOfList(listValue) + case "ucallback.v1.ReadResult.error_code": + value := x.ErrorCode + return protoreflect.ValueOfEnum((protoreflect.EnumNumber)(value)) + default: + if descriptor.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.ReadResult")) + } + panic(fmt.Errorf("message ucallback.v1.ReadResult does not contain field %s", descriptor.FullName())) + } +} + +// Set stores the value for a field. +// +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType. +// When setting a composite type, it is unspecified whether the stored value +// aliases the source's memory in any way. If the composite value is an +// empty, read-only value, then it panics. +// +// Set is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_ReadResult) Set(fd protoreflect.FieldDescriptor, value protoreflect.Value) { + switch fd.FullName() { + case "ucallback.v1.ReadResult.status": + x.Status = (ReadStatus)(value.Enum()) + case "ucallback.v1.ReadResult.result_data": + x.ResultData = value.Bytes() + case "ucallback.v1.ReadResult.aggregates": + lv := value.List() + clv := lv.(*_ReadResult_5_list) + x.Aggregates = *clv.list + case "ucallback.v1.ReadResult.error_code": + x.ErrorCode = (ReadErrorCode)(value.Enum()) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.ReadResult")) + } + panic(fmt.Errorf("message ucallback.v1.ReadResult does not contain field %s", fd.FullName())) + } +} + +// Mutable returns a mutable reference to a composite type. +// +// If the field is unpopulated, it may allocate a composite value. +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType +// if not already stored. +// It panics if the field does not contain a composite type. +// +// Mutable is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_ReadResult) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "ucallback.v1.ReadResult.aggregates": + if x.Aggregates == nil { + x.Aggregates = []*AggregateValue{} + } + value := &_ReadResult_5_list{list: &x.Aggregates} + return protoreflect.ValueOfList(value) + case "ucallback.v1.ReadResult.status": + panic(fmt.Errorf("field status of message ucallback.v1.ReadResult is not mutable")) + case "ucallback.v1.ReadResult.result_data": + panic(fmt.Errorf("field result_data of message ucallback.v1.ReadResult is not mutable")) + case "ucallback.v1.ReadResult.error_code": + panic(fmt.Errorf("field error_code of message ucallback.v1.ReadResult is not mutable")) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.ReadResult")) + } + panic(fmt.Errorf("message ucallback.v1.ReadResult does not contain field %s", fd.FullName())) + } +} + +// NewField returns a new value that is assignable to the field +// for the given descriptor. For scalars, this returns the default value. +// For lists, maps, and messages, this returns a new, empty, mutable value. +func (x *fastReflection_ReadResult) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "ucallback.v1.ReadResult.status": + return protoreflect.ValueOfEnum(0) + case "ucallback.v1.ReadResult.result_data": + return protoreflect.ValueOfBytes(nil) + case "ucallback.v1.ReadResult.aggregates": + list := []*AggregateValue{} + return protoreflect.ValueOfList(&_ReadResult_5_list{list: &list}) + case "ucallback.v1.ReadResult.error_code": + return protoreflect.ValueOfEnum(0) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.ReadResult")) + } + panic(fmt.Errorf("message ucallback.v1.ReadResult does not contain field %s", fd.FullName())) + } +} + +// WhichOneof reports which field within the oneof is populated, +// returning nil if none are populated. +// It panics if the oneof descriptor does not belong to this message. +func (x *fastReflection_ReadResult) WhichOneof(d protoreflect.OneofDescriptor) protoreflect.FieldDescriptor { + switch d.FullName() { + default: + panic(fmt.Errorf("%s is not a oneof field in ucallback.v1.ReadResult", d.FullName())) + } + panic("unreachable") +} + +// GetUnknown retrieves the entire list of unknown fields. +// The caller may only mutate the contents of the RawFields +// if the mutated bytes are stored back into the message with SetUnknown. +func (x *fastReflection_ReadResult) GetUnknown() protoreflect.RawFields { + return x.unknownFields +} + +// SetUnknown stores an entire list of unknown fields. +// The raw fields must be syntactically valid according to the wire format. +// An implementation may panic if this is not the case. +// Once stored, the caller must not mutate the content of the RawFields. +// An empty RawFields may be passed to clear the fields. +// +// SetUnknown is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_ReadResult) SetUnknown(fields protoreflect.RawFields) { + x.unknownFields = fields +} + +// IsValid reports whether the message is valid. +// +// An invalid message is an empty, read-only value. +// +// An invalid message often corresponds to a nil pointer of the concrete +// message type, but the details are implementation dependent. +// Validity is not part of the protobuf data model, and may not +// be preserved in marshaling or other operations. +func (x *fastReflection_ReadResult) IsValid() bool { + return x != nil +} + +// ProtoMethods returns optional fastReflectionFeature-path implementations of various operations. +// This method may return nil. +// +// The returned methods type is identical to +// "google.golang.org/protobuf/runtime/protoiface".Methods. +// Consult the protoiface package documentation for details. +func (x *fastReflection_ReadResult) ProtoMethods() *protoiface.Methods { + size := func(input protoiface.SizeInput) protoiface.SizeOutput { + x := input.Message.Interface().(*ReadResult) + if x == nil { + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: 0, + } + } + options := runtime.SizeInputToOptions(input) + _ = options + var n int + var l int + _ = l + if x.Status != 0 { + n += 1 + runtime.Sov(uint64(x.Status)) + } + l = len(x.ResultData) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } + if len(x.Aggregates) > 0 { + for _, e := range x.Aggregates { + l = options.Size(e) + n += 1 + l + runtime.Sov(uint64(l)) + } + } + if x.ErrorCode != 0 { + n += 1 + runtime.Sov(uint64(x.ErrorCode)) + } + if x.unknownFields != nil { + n += len(x.unknownFields) + } + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: n, + } + } + + marshal := func(input protoiface.MarshalInput) (protoiface.MarshalOutput, error) { + x := input.Message.Interface().(*ReadResult) + if x == nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + options := runtime.MarshalInputToOptions(input) + _ = options + size := options.Size(x) + dAtA := make([]byte, size) + i := len(dAtA) + _ = i + var l int + _ = l + if x.unknownFields != nil { + i -= len(x.unknownFields) + copy(dAtA[i:], x.unknownFields) + } + if x.ErrorCode != 0 { + i = runtime.EncodeVarint(dAtA, i, uint64(x.ErrorCode)) + i-- + dAtA[i] = 0x30 + } + if len(x.Aggregates) > 0 { + for iNdEx := len(x.Aggregates) - 1; iNdEx >= 0; iNdEx-- { + encoded, err := options.Marshal(x.Aggregates[iNdEx]) + if err != nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, err + } + i -= len(encoded) + copy(dAtA[i:], encoded) + i = runtime.EncodeVarint(dAtA, i, uint64(len(encoded))) + i-- + dAtA[i] = 0x2a + } + } + if len(x.ResultData) > 0 { + i -= len(x.ResultData) + copy(dAtA[i:], x.ResultData) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.ResultData))) + i-- + dAtA[i] = 0x12 + } + if x.Status != 0 { + i = runtime.EncodeVarint(dAtA, i, uint64(x.Status)) + i-- + dAtA[i] = 0x8 + } + if input.Buf != nil { + input.Buf = append(input.Buf, dAtA...) + } else { + input.Buf = dAtA + } + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + unmarshal := func(input protoiface.UnmarshalInput) (protoiface.UnmarshalOutput, error) { + x := input.Message.Interface().(*ReadResult) + if x == nil { + return protoiface.UnmarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Flags: input.Flags, + }, nil + } + options := runtime.UnmarshalInputToOptions(input) + _ = options + dAtA := input.Buf + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: ReadResult: wiretype end group for non-group") + } + if fieldNum <= 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: ReadResult: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Status", wireType) + } + x.Status = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + x.Status |= ReadStatus(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field ResultData", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.ResultData = append(x.ResultData[:0], dAtA[iNdEx:postIndex]...) + if x.ResultData == nil { + x.ResultData = []byte{} + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Aggregates", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.Aggregates = append(x.Aggregates, &AggregateValue{}) + if err := options.Unmarshal(dAtA[iNdEx:postIndex], x.Aggregates[len(x.Aggregates)-1]); err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + iNdEx = postIndex + case 6: + if wireType != 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field ErrorCode", wireType) + } + x.ErrorCode = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + x.ErrorCode |= ReadErrorCode(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := runtime.Skip(dAtA[iNdEx:]) + if err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if !options.DiscardUnknown { + x.unknownFields = append(x.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + } + iNdEx += skippy + } + } + + if iNdEx > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, nil + } + return &protoiface.Methods{ + NoUnkeyedLiterals: struct{}{}, + Flags: protoiface.SupportMarshalDeterministic | protoiface.SupportUnmarshalDiscardUnknown, + Size: size, + Marshal: marshal, + Unmarshal: unmarshal, + Merge: nil, + CheckInitialized: nil, + } +} + +var ( + md_AggregateValue protoreflect.MessageDescriptor + fd_AggregateValue_extract_index protoreflect.FieldDescriptor + fd_AggregateValue_mode protoreflect.FieldDescriptor + fd_AggregateValue_value protoreflect.FieldDescriptor +) + +func init() { + file_ucallback_v1_types_proto_init() + md_AggregateValue = File_ucallback_v1_types_proto.Messages().ByName("AggregateValue") + fd_AggregateValue_extract_index = md_AggregateValue.Fields().ByName("extract_index") + fd_AggregateValue_mode = md_AggregateValue.Fields().ByName("mode") + fd_AggregateValue_value = md_AggregateValue.Fields().ByName("value") +} + +var _ protoreflect.Message = (*fastReflection_AggregateValue)(nil) + +type fastReflection_AggregateValue AggregateValue + +func (x *AggregateValue) ProtoReflect() protoreflect.Message { + return (*fastReflection_AggregateValue)(x) +} + +func (x *AggregateValue) slowProtoReflect() protoreflect.Message { + mi := &file_ucallback_v1_types_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +var _fastReflection_AggregateValue_messageType fastReflection_AggregateValue_messageType +var _ protoreflect.MessageType = fastReflection_AggregateValue_messageType{} + +type fastReflection_AggregateValue_messageType struct{} + +func (x fastReflection_AggregateValue_messageType) Zero() protoreflect.Message { + return (*fastReflection_AggregateValue)(nil) +} +func (x fastReflection_AggregateValue_messageType) New() protoreflect.Message { + return new(fastReflection_AggregateValue) +} +func (x fastReflection_AggregateValue_messageType) Descriptor() protoreflect.MessageDescriptor { + return md_AggregateValue +} + +// Descriptor returns message descriptor, which contains only the protobuf +// type information for the message. +func (x *fastReflection_AggregateValue) Descriptor() protoreflect.MessageDescriptor { + return md_AggregateValue +} + +// Type returns the message type, which encapsulates both Go and protobuf +// type information. If the Go type information is not needed, +// it is recommended that the message descriptor be used instead. +func (x *fastReflection_AggregateValue) Type() protoreflect.MessageType { + return _fastReflection_AggregateValue_messageType +} + +// New returns a newly allocated and mutable empty message. +func (x *fastReflection_AggregateValue) New() protoreflect.Message { + return new(fastReflection_AggregateValue) +} + +// Interface unwraps the message reflection interface and +// returns the underlying ProtoMessage interface. +func (x *fastReflection_AggregateValue) Interface() protoreflect.ProtoMessage { + return (*AggregateValue)(x) +} + +// Range iterates over every populated field in an undefined order, +// calling f for each field descriptor and value encountered. +// Range returns immediately if f returns false. +// While iterating, mutating operations may only be performed +// on the current field descriptor. +func (x *fastReflection_AggregateValue) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { + if x.ExtractIndex != uint32(0) { + value := protoreflect.ValueOfUint32(x.ExtractIndex) + if !f(fd_AggregateValue_extract_index, value) { + return + } + } + if x.Mode != uint32(0) { + value := protoreflect.ValueOfUint32(x.Mode) + if !f(fd_AggregateValue_mode, value) { + return + } + } + if len(x.Value) != 0 { + value := protoreflect.ValueOfBytes(x.Value) + if !f(fd_AggregateValue_value, value) { + return + } + } +} + +// Has reports whether a field is populated. +// +// Some fields have the property of nullability where it is possible to +// distinguish between the default value of a field and whether the field +// was explicitly populated with the default value. Singular message fields, +// member fields of a oneof, and proto2 scalar fields are nullable. Such +// fields are populated only if explicitly set. +// +// In other cases (aside from the nullable cases above), +// a proto3 scalar field is populated if it contains a non-zero value, and +// a repeated field is populated if it is non-empty. +func (x *fastReflection_AggregateValue) Has(fd protoreflect.FieldDescriptor) bool { + switch fd.FullName() { + case "ucallback.v1.AggregateValue.extract_index": + return x.ExtractIndex != uint32(0) + case "ucallback.v1.AggregateValue.mode": + return x.Mode != uint32(0) + case "ucallback.v1.AggregateValue.value": + return len(x.Value) != 0 + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.AggregateValue")) + } + panic(fmt.Errorf("message ucallback.v1.AggregateValue does not contain field %s", fd.FullName())) + } +} + +// Clear clears the field such that a subsequent Has call reports false. +// +// Clearing an extension field clears both the extension type and value +// associated with the given field number. +// +// Clear is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_AggregateValue) Clear(fd protoreflect.FieldDescriptor) { + switch fd.FullName() { + case "ucallback.v1.AggregateValue.extract_index": + x.ExtractIndex = uint32(0) + case "ucallback.v1.AggregateValue.mode": + x.Mode = uint32(0) + case "ucallback.v1.AggregateValue.value": + x.Value = nil + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.AggregateValue")) + } + panic(fmt.Errorf("message ucallback.v1.AggregateValue does not contain field %s", fd.FullName())) + } +} + +// Get retrieves the value for a field. +// +// For unpopulated scalars, it returns the default value, where +// the default value of a bytes scalar is guaranteed to be a copy. +// For unpopulated composite types, it returns an empty, read-only view +// of the value; to obtain a mutable reference, use Mutable. +func (x *fastReflection_AggregateValue) Get(descriptor protoreflect.FieldDescriptor) protoreflect.Value { + switch descriptor.FullName() { + case "ucallback.v1.AggregateValue.extract_index": + value := x.ExtractIndex + return protoreflect.ValueOfUint32(value) + case "ucallback.v1.AggregateValue.mode": + value := x.Mode + return protoreflect.ValueOfUint32(value) + case "ucallback.v1.AggregateValue.value": + value := x.Value + return protoreflect.ValueOfBytes(value) + default: + if descriptor.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.AggregateValue")) + } + panic(fmt.Errorf("message ucallback.v1.AggregateValue does not contain field %s", descriptor.FullName())) + } +} + +// Set stores the value for a field. +// +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType. +// When setting a composite type, it is unspecified whether the stored value +// aliases the source's memory in any way. If the composite value is an +// empty, read-only value, then it panics. +// +// Set is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_AggregateValue) Set(fd protoreflect.FieldDescriptor, value protoreflect.Value) { + switch fd.FullName() { + case "ucallback.v1.AggregateValue.extract_index": + x.ExtractIndex = uint32(value.Uint()) + case "ucallback.v1.AggregateValue.mode": + x.Mode = uint32(value.Uint()) + case "ucallback.v1.AggregateValue.value": + x.Value = value.Bytes() + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.AggregateValue")) + } + panic(fmt.Errorf("message ucallback.v1.AggregateValue does not contain field %s", fd.FullName())) + } +} + +// Mutable returns a mutable reference to a composite type. +// +// If the field is unpopulated, it may allocate a composite value. +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType +// if not already stored. +// It panics if the field does not contain a composite type. +// +// Mutable is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_AggregateValue) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "ucallback.v1.AggregateValue.extract_index": + panic(fmt.Errorf("field extract_index of message ucallback.v1.AggregateValue is not mutable")) + case "ucallback.v1.AggregateValue.mode": + panic(fmt.Errorf("field mode of message ucallback.v1.AggregateValue is not mutable")) + case "ucallback.v1.AggregateValue.value": + panic(fmt.Errorf("field value of message ucallback.v1.AggregateValue is not mutable")) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.AggregateValue")) + } + panic(fmt.Errorf("message ucallback.v1.AggregateValue does not contain field %s", fd.FullName())) + } +} + +// NewField returns a new value that is assignable to the field +// for the given descriptor. For scalars, this returns the default value. +// For lists, maps, and messages, this returns a new, empty, mutable value. +func (x *fastReflection_AggregateValue) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "ucallback.v1.AggregateValue.extract_index": + return protoreflect.ValueOfUint32(uint32(0)) + case "ucallback.v1.AggregateValue.mode": + return protoreflect.ValueOfUint32(uint32(0)) + case "ucallback.v1.AggregateValue.value": + return protoreflect.ValueOfBytes(nil) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.AggregateValue")) + } + panic(fmt.Errorf("message ucallback.v1.AggregateValue does not contain field %s", fd.FullName())) + } +} + +// WhichOneof reports which field within the oneof is populated, +// returning nil if none are populated. +// It panics if the oneof descriptor does not belong to this message. +func (x *fastReflection_AggregateValue) WhichOneof(d protoreflect.OneofDescriptor) protoreflect.FieldDescriptor { + switch d.FullName() { + default: + panic(fmt.Errorf("%s is not a oneof field in ucallback.v1.AggregateValue", d.FullName())) + } + panic("unreachable") +} + +// GetUnknown retrieves the entire list of unknown fields. +// The caller may only mutate the contents of the RawFields +// if the mutated bytes are stored back into the message with SetUnknown. +func (x *fastReflection_AggregateValue) GetUnknown() protoreflect.RawFields { + return x.unknownFields +} + +// SetUnknown stores an entire list of unknown fields. +// The raw fields must be syntactically valid according to the wire format. +// An implementation may panic if this is not the case. +// Once stored, the caller must not mutate the content of the RawFields. +// An empty RawFields may be passed to clear the fields. +// +// SetUnknown is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_AggregateValue) SetUnknown(fields protoreflect.RawFields) { + x.unknownFields = fields +} + +// IsValid reports whether the message is valid. +// +// An invalid message is an empty, read-only value. +// +// An invalid message often corresponds to a nil pointer of the concrete +// message type, but the details are implementation dependent. +// Validity is not part of the protobuf data model, and may not +// be preserved in marshaling or other operations. +func (x *fastReflection_AggregateValue) IsValid() bool { + return x != nil +} + +// ProtoMethods returns optional fastReflectionFeature-path implementations of various operations. +// This method may return nil. +// +// The returned methods type is identical to +// "google.golang.org/protobuf/runtime/protoiface".Methods. +// Consult the protoiface package documentation for details. +func (x *fastReflection_AggregateValue) ProtoMethods() *protoiface.Methods { + size := func(input protoiface.SizeInput) protoiface.SizeOutput { + x := input.Message.Interface().(*AggregateValue) + if x == nil { + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: 0, + } + } + options := runtime.SizeInputToOptions(input) + _ = options + var n int + var l int + _ = l + if x.ExtractIndex != 0 { + n += 1 + runtime.Sov(uint64(x.ExtractIndex)) + } + if x.Mode != 0 { + n += 1 + runtime.Sov(uint64(x.Mode)) + } + l = len(x.Value) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } + if x.unknownFields != nil { + n += len(x.unknownFields) + } + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: n, + } + } + + marshal := func(input protoiface.MarshalInput) (protoiface.MarshalOutput, error) { + x := input.Message.Interface().(*AggregateValue) + if x == nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + options := runtime.MarshalInputToOptions(input) + _ = options + size := options.Size(x) + dAtA := make([]byte, size) + i := len(dAtA) + _ = i + var l int + _ = l + if x.unknownFields != nil { + i -= len(x.unknownFields) + copy(dAtA[i:], x.unknownFields) + } + if len(x.Value) > 0 { + i -= len(x.Value) + copy(dAtA[i:], x.Value) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.Value))) + i-- + dAtA[i] = 0x1a + } + if x.Mode != 0 { + i = runtime.EncodeVarint(dAtA, i, uint64(x.Mode)) + i-- + dAtA[i] = 0x10 + } + if x.ExtractIndex != 0 { + i = runtime.EncodeVarint(dAtA, i, uint64(x.ExtractIndex)) + i-- + dAtA[i] = 0x8 + } + if input.Buf != nil { + input.Buf = append(input.Buf, dAtA...) + } else { + input.Buf = dAtA + } + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + unmarshal := func(input protoiface.UnmarshalInput) (protoiface.UnmarshalOutput, error) { + x := input.Message.Interface().(*AggregateValue) + if x == nil { + return protoiface.UnmarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Flags: input.Flags, + }, nil + } + options := runtime.UnmarshalInputToOptions(input) + _ = options + dAtA := input.Buf + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: AggregateValue: wiretype end group for non-group") + } + if fieldNum <= 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: AggregateValue: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field ExtractIndex", wireType) + } + x.ExtractIndex = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + x.ExtractIndex |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Mode", wireType) + } + x.Mode = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + x.Mode |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Value", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.Value = append(x.Value[:0], dAtA[iNdEx:postIndex]...) + if x.Value == nil { + x.Value = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := runtime.Skip(dAtA[iNdEx:]) + if err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if !options.DiscardUnknown { + x.unknownFields = append(x.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + } + iNdEx += skippy + } + } + + if iNdEx > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, nil + } + return &protoiface.Methods{ + NoUnkeyedLiterals: struct{}{}, + Flags: protoiface.SupportMarshalDeterministic | protoiface.SupportUnmarshalDiscardUnknown, + Size: size, + Marshal: marshal, + Unmarshal: unmarshal, + Merge: nil, + CheckInitialized: nil, + } +} + +var _ protoreflect.List = (*_UniversalRead_6_list)(nil) + +type _UniversalRead_6_list struct { + list *[]*v1.PCTx +} + +func (x *_UniversalRead_6_list) Len() int { + if x.list == nil { + return 0 + } + return len(*x.list) +} + +func (x *_UniversalRead_6_list) Get(i int) protoreflect.Value { + return protoreflect.ValueOfMessage((*x.list)[i].ProtoReflect()) +} + +func (x *_UniversalRead_6_list) Set(i int, value protoreflect.Value) { + valueUnwrapped := value.Message() + concreteValue := valueUnwrapped.Interface().(*v1.PCTx) + (*x.list)[i] = concreteValue +} + +func (x *_UniversalRead_6_list) Append(value protoreflect.Value) { + valueUnwrapped := value.Message() + concreteValue := valueUnwrapped.Interface().(*v1.PCTx) + *x.list = append(*x.list, concreteValue) +} + +func (x *_UniversalRead_6_list) AppendMutable() protoreflect.Value { + v := new(v1.PCTx) + *x.list = append(*x.list, v) + return protoreflect.ValueOfMessage(v.ProtoReflect()) +} + +func (x *_UniversalRead_6_list) Truncate(n int) { + for i := n; i < len(*x.list); i++ { + (*x.list)[i] = nil + } + *x.list = (*x.list)[:n] +} + +func (x *_UniversalRead_6_list) NewElement() protoreflect.Value { + v := new(v1.PCTx) + return protoreflect.ValueOfMessage(v.ProtoReflect()) +} + +func (x *_UniversalRead_6_list) IsValid() bool { + return x.list != nil +} + +var ( + md_UniversalRead protoreflect.MessageDescriptor + fd_UniversalRead_id protoreflect.FieldDescriptor + fd_UniversalRead_request protoreflect.FieldDescriptor + fd_UniversalRead_result protoreflect.FieldDescriptor + fd_UniversalRead_status protoreflect.FieldDescriptor + fd_UniversalRead_ballot_key protoreflect.FieldDescriptor + fd_UniversalRead_pc_tx protoreflect.FieldDescriptor + fd_UniversalRead_error_msg protoreflect.FieldDescriptor + fd_UniversalRead_expiry_attempts protoreflect.FieldDescriptor +) + +func init() { + file_ucallback_v1_types_proto_init() + md_UniversalRead = File_ucallback_v1_types_proto.Messages().ByName("UniversalRead") + fd_UniversalRead_id = md_UniversalRead.Fields().ByName("id") + fd_UniversalRead_request = md_UniversalRead.Fields().ByName("request") + fd_UniversalRead_result = md_UniversalRead.Fields().ByName("result") + fd_UniversalRead_status = md_UniversalRead.Fields().ByName("status") + fd_UniversalRead_ballot_key = md_UniversalRead.Fields().ByName("ballot_key") + fd_UniversalRead_pc_tx = md_UniversalRead.Fields().ByName("pc_tx") + fd_UniversalRead_error_msg = md_UniversalRead.Fields().ByName("error_msg") + fd_UniversalRead_expiry_attempts = md_UniversalRead.Fields().ByName("expiry_attempts") +} + +var _ protoreflect.Message = (*fastReflection_UniversalRead)(nil) + +type fastReflection_UniversalRead UniversalRead + +func (x *UniversalRead) ProtoReflect() protoreflect.Message { + return (*fastReflection_UniversalRead)(x) +} + +func (x *UniversalRead) slowProtoReflect() protoreflect.Message { + mi := &file_ucallback_v1_types_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +var _fastReflection_UniversalRead_messageType fastReflection_UniversalRead_messageType +var _ protoreflect.MessageType = fastReflection_UniversalRead_messageType{} + +type fastReflection_UniversalRead_messageType struct{} + +func (x fastReflection_UniversalRead_messageType) Zero() protoreflect.Message { + return (*fastReflection_UniversalRead)(nil) +} +func (x fastReflection_UniversalRead_messageType) New() protoreflect.Message { + return new(fastReflection_UniversalRead) +} +func (x fastReflection_UniversalRead_messageType) Descriptor() protoreflect.MessageDescriptor { + return md_UniversalRead +} + +// Descriptor returns message descriptor, which contains only the protobuf +// type information for the message. +func (x *fastReflection_UniversalRead) Descriptor() protoreflect.MessageDescriptor { + return md_UniversalRead +} + +// Type returns the message type, which encapsulates both Go and protobuf +// type information. If the Go type information is not needed, +// it is recommended that the message descriptor be used instead. +func (x *fastReflection_UniversalRead) Type() protoreflect.MessageType { + return _fastReflection_UniversalRead_messageType +} + +// New returns a newly allocated and mutable empty message. +func (x *fastReflection_UniversalRead) New() protoreflect.Message { + return new(fastReflection_UniversalRead) +} + +// Interface unwraps the message reflection interface and +// returns the underlying ProtoMessage interface. +func (x *fastReflection_UniversalRead) Interface() protoreflect.ProtoMessage { + return (*UniversalRead)(x) +} + +// Range iterates over every populated field in an undefined order, +// calling f for each field descriptor and value encountered. +// Range returns immediately if f returns false. +// While iterating, mutating operations may only be performed +// on the current field descriptor. +func (x *fastReflection_UniversalRead) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { + if x.Id != "" { + value := protoreflect.ValueOfString(x.Id) + if !f(fd_UniversalRead_id, value) { + return + } + } + if x.Request != nil { + value := protoreflect.ValueOfMessage(x.Request.ProtoReflect()) + if !f(fd_UniversalRead_request, value) { + return + } + } + if x.Result != nil { + value := protoreflect.ValueOfMessage(x.Result.ProtoReflect()) + if !f(fd_UniversalRead_result, value) { + return + } + } + if x.Status != 0 { + value := protoreflect.ValueOfEnum((protoreflect.EnumNumber)(x.Status)) + if !f(fd_UniversalRead_status, value) { + return + } + } + if x.BallotKey != "" { + value := protoreflect.ValueOfString(x.BallotKey) + if !f(fd_UniversalRead_ballot_key, value) { + return + } + } + if len(x.PcTx) != 0 { + value := protoreflect.ValueOfList(&_UniversalRead_6_list{list: &x.PcTx}) + if !f(fd_UniversalRead_pc_tx, value) { + return + } + } + if x.ErrorMsg != "" { + value := protoreflect.ValueOfString(x.ErrorMsg) + if !f(fd_UniversalRead_error_msg, value) { + return + } + } + if x.ExpiryAttempts != uint32(0) { + value := protoreflect.ValueOfUint32(x.ExpiryAttempts) + if !f(fd_UniversalRead_expiry_attempts, value) { + return + } + } +} + +// Has reports whether a field is populated. +// +// Some fields have the property of nullability where it is possible to +// distinguish between the default value of a field and whether the field +// was explicitly populated with the default value. Singular message fields, +// member fields of a oneof, and proto2 scalar fields are nullable. Such +// fields are populated only if explicitly set. +// +// In other cases (aside from the nullable cases above), +// a proto3 scalar field is populated if it contains a non-zero value, and +// a repeated field is populated if it is non-empty. +func (x *fastReflection_UniversalRead) Has(fd protoreflect.FieldDescriptor) bool { + switch fd.FullName() { + case "ucallback.v1.UniversalRead.id": + return x.Id != "" + case "ucallback.v1.UniversalRead.request": + return x.Request != nil + case "ucallback.v1.UniversalRead.result": + return x.Result != nil + case "ucallback.v1.UniversalRead.status": + return x.Status != 0 + case "ucallback.v1.UniversalRead.ballot_key": + return x.BallotKey != "" + case "ucallback.v1.UniversalRead.pc_tx": + return len(x.PcTx) != 0 + case "ucallback.v1.UniversalRead.error_msg": + return x.ErrorMsg != "" + case "ucallback.v1.UniversalRead.expiry_attempts": + return x.ExpiryAttempts != uint32(0) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.UniversalRead")) + } + panic(fmt.Errorf("message ucallback.v1.UniversalRead does not contain field %s", fd.FullName())) + } +} + +// Clear clears the field such that a subsequent Has call reports false. +// +// Clearing an extension field clears both the extension type and value +// associated with the given field number. +// +// Clear is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_UniversalRead) Clear(fd protoreflect.FieldDescriptor) { + switch fd.FullName() { + case "ucallback.v1.UniversalRead.id": + x.Id = "" + case "ucallback.v1.UniversalRead.request": + x.Request = nil + case "ucallback.v1.UniversalRead.result": + x.Result = nil + case "ucallback.v1.UniversalRead.status": + x.Status = 0 + case "ucallback.v1.UniversalRead.ballot_key": + x.BallotKey = "" + case "ucallback.v1.UniversalRead.pc_tx": + x.PcTx = nil + case "ucallback.v1.UniversalRead.error_msg": + x.ErrorMsg = "" + case "ucallback.v1.UniversalRead.expiry_attempts": + x.ExpiryAttempts = uint32(0) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.UniversalRead")) + } + panic(fmt.Errorf("message ucallback.v1.UniversalRead does not contain field %s", fd.FullName())) + } +} + +// Get retrieves the value for a field. +// +// For unpopulated scalars, it returns the default value, where +// the default value of a bytes scalar is guaranteed to be a copy. +// For unpopulated composite types, it returns an empty, read-only view +// of the value; to obtain a mutable reference, use Mutable. +func (x *fastReflection_UniversalRead) Get(descriptor protoreflect.FieldDescriptor) protoreflect.Value { + switch descriptor.FullName() { + case "ucallback.v1.UniversalRead.id": + value := x.Id + return protoreflect.ValueOfString(value) + case "ucallback.v1.UniversalRead.request": + value := x.Request + return protoreflect.ValueOfMessage(value.ProtoReflect()) + case "ucallback.v1.UniversalRead.result": + value := x.Result + return protoreflect.ValueOfMessage(value.ProtoReflect()) + case "ucallback.v1.UniversalRead.status": + value := x.Status + return protoreflect.ValueOfEnum((protoreflect.EnumNumber)(value)) + case "ucallback.v1.UniversalRead.ballot_key": + value := x.BallotKey + return protoreflect.ValueOfString(value) + case "ucallback.v1.UniversalRead.pc_tx": + if len(x.PcTx) == 0 { + return protoreflect.ValueOfList(&_UniversalRead_6_list{}) + } + listValue := &_UniversalRead_6_list{list: &x.PcTx} + return protoreflect.ValueOfList(listValue) + case "ucallback.v1.UniversalRead.error_msg": + value := x.ErrorMsg + return protoreflect.ValueOfString(value) + case "ucallback.v1.UniversalRead.expiry_attempts": + value := x.ExpiryAttempts + return protoreflect.ValueOfUint32(value) + default: + if descriptor.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.UniversalRead")) + } + panic(fmt.Errorf("message ucallback.v1.UniversalRead does not contain field %s", descriptor.FullName())) + } +} + +// Set stores the value for a field. +// +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType. +// When setting a composite type, it is unspecified whether the stored value +// aliases the source's memory in any way. If the composite value is an +// empty, read-only value, then it panics. +// +// Set is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_UniversalRead) Set(fd protoreflect.FieldDescriptor, value protoreflect.Value) { + switch fd.FullName() { + case "ucallback.v1.UniversalRead.id": + x.Id = value.Interface().(string) + case "ucallback.v1.UniversalRead.request": + x.Request = value.Message().Interface().(*ReadRequest) + case "ucallback.v1.UniversalRead.result": + x.Result = value.Message().Interface().(*ReadResult) + case "ucallback.v1.UniversalRead.status": + x.Status = (UniversalReadStatus)(value.Enum()) + case "ucallback.v1.UniversalRead.ballot_key": + x.BallotKey = value.Interface().(string) + case "ucallback.v1.UniversalRead.pc_tx": + lv := value.List() + clv := lv.(*_UniversalRead_6_list) + x.PcTx = *clv.list + case "ucallback.v1.UniversalRead.error_msg": + x.ErrorMsg = value.Interface().(string) + case "ucallback.v1.UniversalRead.expiry_attempts": + x.ExpiryAttempts = uint32(value.Uint()) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.UniversalRead")) + } + panic(fmt.Errorf("message ucallback.v1.UniversalRead does not contain field %s", fd.FullName())) + } +} + +// Mutable returns a mutable reference to a composite type. +// +// If the field is unpopulated, it may allocate a composite value. +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType +// if not already stored. +// It panics if the field does not contain a composite type. +// +// Mutable is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_UniversalRead) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "ucallback.v1.UniversalRead.request": + if x.Request == nil { + x.Request = new(ReadRequest) + } + return protoreflect.ValueOfMessage(x.Request.ProtoReflect()) + case "ucallback.v1.UniversalRead.result": + if x.Result == nil { + x.Result = new(ReadResult) + } + return protoreflect.ValueOfMessage(x.Result.ProtoReflect()) + case "ucallback.v1.UniversalRead.pc_tx": + if x.PcTx == nil { + x.PcTx = []*v1.PCTx{} + } + value := &_UniversalRead_6_list{list: &x.PcTx} + return protoreflect.ValueOfList(value) + case "ucallback.v1.UniversalRead.id": + panic(fmt.Errorf("field id of message ucallback.v1.UniversalRead is not mutable")) + case "ucallback.v1.UniversalRead.status": + panic(fmt.Errorf("field status of message ucallback.v1.UniversalRead is not mutable")) + case "ucallback.v1.UniversalRead.ballot_key": + panic(fmt.Errorf("field ballot_key of message ucallback.v1.UniversalRead is not mutable")) + case "ucallback.v1.UniversalRead.error_msg": + panic(fmt.Errorf("field error_msg of message ucallback.v1.UniversalRead is not mutable")) + case "ucallback.v1.UniversalRead.expiry_attempts": + panic(fmt.Errorf("field expiry_attempts of message ucallback.v1.UniversalRead is not mutable")) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.UniversalRead")) + } + panic(fmt.Errorf("message ucallback.v1.UniversalRead does not contain field %s", fd.FullName())) + } +} + +// NewField returns a new value that is assignable to the field +// for the given descriptor. For scalars, this returns the default value. +// For lists, maps, and messages, this returns a new, empty, mutable value. +func (x *fastReflection_UniversalRead) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "ucallback.v1.UniversalRead.id": + return protoreflect.ValueOfString("") + case "ucallback.v1.UniversalRead.request": + m := new(ReadRequest) + return protoreflect.ValueOfMessage(m.ProtoReflect()) + case "ucallback.v1.UniversalRead.result": + m := new(ReadResult) + return protoreflect.ValueOfMessage(m.ProtoReflect()) + case "ucallback.v1.UniversalRead.status": + return protoreflect.ValueOfEnum(0) + case "ucallback.v1.UniversalRead.ballot_key": + return protoreflect.ValueOfString("") + case "ucallback.v1.UniversalRead.pc_tx": + list := []*v1.PCTx{} + return protoreflect.ValueOfList(&_UniversalRead_6_list{list: &list}) + case "ucallback.v1.UniversalRead.error_msg": + return protoreflect.ValueOfString("") + case "ucallback.v1.UniversalRead.expiry_attempts": + return protoreflect.ValueOfUint32(uint32(0)) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ucallback.v1.UniversalRead")) + } + panic(fmt.Errorf("message ucallback.v1.UniversalRead does not contain field %s", fd.FullName())) + } +} + +// WhichOneof reports which field within the oneof is populated, +// returning nil if none are populated. +// It panics if the oneof descriptor does not belong to this message. +func (x *fastReflection_UniversalRead) WhichOneof(d protoreflect.OneofDescriptor) protoreflect.FieldDescriptor { + switch d.FullName() { + default: + panic(fmt.Errorf("%s is not a oneof field in ucallback.v1.UniversalRead", d.FullName())) + } + panic("unreachable") +} + +// GetUnknown retrieves the entire list of unknown fields. +// The caller may only mutate the contents of the RawFields +// if the mutated bytes are stored back into the message with SetUnknown. +func (x *fastReflection_UniversalRead) GetUnknown() protoreflect.RawFields { + return x.unknownFields +} + +// SetUnknown stores an entire list of unknown fields. +// The raw fields must be syntactically valid according to the wire format. +// An implementation may panic if this is not the case. +// Once stored, the caller must not mutate the content of the RawFields. +// An empty RawFields may be passed to clear the fields. +// +// SetUnknown is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_UniversalRead) SetUnknown(fields protoreflect.RawFields) { + x.unknownFields = fields +} + +// IsValid reports whether the message is valid. +// +// An invalid message is an empty, read-only value. +// +// An invalid message often corresponds to a nil pointer of the concrete +// message type, but the details are implementation dependent. +// Validity is not part of the protobuf data model, and may not +// be preserved in marshaling or other operations. +func (x *fastReflection_UniversalRead) IsValid() bool { + return x != nil +} + +// ProtoMethods returns optional fastReflectionFeature-path implementations of various operations. +// This method may return nil. +// +// The returned methods type is identical to +// "google.golang.org/protobuf/runtime/protoiface".Methods. +// Consult the protoiface package documentation for details. +func (x *fastReflection_UniversalRead) ProtoMethods() *protoiface.Methods { + size := func(input protoiface.SizeInput) protoiface.SizeOutput { + x := input.Message.Interface().(*UniversalRead) + if x == nil { + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: 0, + } + } + options := runtime.SizeInputToOptions(input) + _ = options + var n int + var l int + _ = l + l = len(x.Id) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } + if x.Request != nil { + l = options.Size(x.Request) + n += 1 + l + runtime.Sov(uint64(l)) + } + if x.Result != nil { + l = options.Size(x.Result) + n += 1 + l + runtime.Sov(uint64(l)) + } + if x.Status != 0 { + n += 1 + runtime.Sov(uint64(x.Status)) + } + l = len(x.BallotKey) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } + if len(x.PcTx) > 0 { + for _, e := range x.PcTx { + l = options.Size(e) + n += 1 + l + runtime.Sov(uint64(l)) + } + } + l = len(x.ErrorMsg) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } + if x.ExpiryAttempts != 0 { + n += 1 + runtime.Sov(uint64(x.ExpiryAttempts)) + } + if x.unknownFields != nil { + n += len(x.unknownFields) + } + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: n, + } + } + + marshal := func(input protoiface.MarshalInput) (protoiface.MarshalOutput, error) { + x := input.Message.Interface().(*UniversalRead) + if x == nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + options := runtime.MarshalInputToOptions(input) + _ = options + size := options.Size(x) + dAtA := make([]byte, size) + i := len(dAtA) + _ = i + var l int + _ = l + if x.unknownFields != nil { + i -= len(x.unknownFields) + copy(dAtA[i:], x.unknownFields) + } + if x.ExpiryAttempts != 0 { + i = runtime.EncodeVarint(dAtA, i, uint64(x.ExpiryAttempts)) + i-- + dAtA[i] = 0x40 + } + if len(x.ErrorMsg) > 0 { + i -= len(x.ErrorMsg) + copy(dAtA[i:], x.ErrorMsg) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.ErrorMsg))) + i-- + dAtA[i] = 0x3a + } + if len(x.PcTx) > 0 { + for iNdEx := len(x.PcTx) - 1; iNdEx >= 0; iNdEx-- { + encoded, err := options.Marshal(x.PcTx[iNdEx]) + if err != nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, err + } + i -= len(encoded) + copy(dAtA[i:], encoded) + i = runtime.EncodeVarint(dAtA, i, uint64(len(encoded))) + i-- + dAtA[i] = 0x32 + } + } + if len(x.BallotKey) > 0 { + i -= len(x.BallotKey) + copy(dAtA[i:], x.BallotKey) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.BallotKey))) + i-- + dAtA[i] = 0x2a + } + if x.Status != 0 { + i = runtime.EncodeVarint(dAtA, i, uint64(x.Status)) + i-- + dAtA[i] = 0x20 + } + if x.Result != nil { + encoded, err := options.Marshal(x.Result) + if err != nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, err + } + i -= len(encoded) + copy(dAtA[i:], encoded) + i = runtime.EncodeVarint(dAtA, i, uint64(len(encoded))) + i-- + dAtA[i] = 0x1a + } + if x.Request != nil { + encoded, err := options.Marshal(x.Request) + if err != nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, err + } + i -= len(encoded) + copy(dAtA[i:], encoded) + i = runtime.EncodeVarint(dAtA, i, uint64(len(encoded))) + i-- + dAtA[i] = 0x12 + } + if len(x.Id) > 0 { + i -= len(x.Id) + copy(dAtA[i:], x.Id) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.Id))) + i-- + dAtA[i] = 0xa + } + if input.Buf != nil { + input.Buf = append(input.Buf, dAtA...) + } else { + input.Buf = dAtA + } + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + unmarshal := func(input protoiface.UnmarshalInput) (protoiface.UnmarshalOutput, error) { + x := input.Message.Interface().(*UniversalRead) + if x == nil { + return protoiface.UnmarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Flags: input.Flags, + }, nil + } + options := runtime.UnmarshalInputToOptions(input) + _ = options + dAtA := input.Buf + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: UniversalRead: wiretype end group for non-group") + } + if fieldNum <= 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: UniversalRead: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Id", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.Id = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Request", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if x.Request == nil { + x.Request = &ReadRequest{} + } + if err := options.Unmarshal(dAtA[iNdEx:postIndex], x.Request); err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Result", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if x.Result == nil { + x.Result = &ReadResult{} + } + if err := options.Unmarshal(dAtA[iNdEx:postIndex], x.Result); err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + iNdEx = postIndex + case 4: + if wireType != 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Status", wireType) + } + x.Status = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + x.Status |= UniversalReadStatus(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field BallotKey", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.BallotKey = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 6: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field PcTx", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.PcTx = append(x.PcTx, &v1.PCTx{}) + if err := options.Unmarshal(dAtA[iNdEx:postIndex], x.PcTx[len(x.PcTx)-1]); err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + iNdEx = postIndex + case 7: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field ErrorMsg", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.ErrorMsg = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 8: + if wireType != 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field ExpiryAttempts", wireType) + } + x.ExpiryAttempts = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + x.ExpiryAttempts |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := runtime.Skip(dAtA[iNdEx:]) + if err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if !options.DiscardUnknown { + x.unknownFields = append(x.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + } + iNdEx += skippy + } + } + + if iNdEx > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, nil + } + return &protoiface.Methods{ + NoUnkeyedLiterals: struct{}{}, + Flags: protoiface.SupportMarshalDeterministic | protoiface.SupportUnmarshalDiscardUnknown, + Size: size, + Marshal: marshal, + Unmarshal: unmarshal, + Merge: nil, + CheckInitialized: nil, + } +} + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.27.0 +// protoc (unknown) +// source: ucallback/v1/types.proto + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// ReadStatus is the outcome a universal validator observed for a read. +// ReadErrorCode is the deterministic reason a read produced an ERROR observation. +// Only non-transient failures appear here; transient failures never vote — the +// validator retries locally instead. +type ReadErrorCode int32 + +const ( + ReadErrorCode_READ_ERROR_UNSPECIFIED ReadErrorCode = 0 // catch-all / other + ReadErrorCode_READ_ERROR_INVALID_QUERY ReadErrorCode = 1 // envelope or params could not be decoded for this chain + ReadErrorCode_READ_ERROR_UNSUPPORTED ReadErrorCode = 2 // chain does not support this query type or option + ReadErrorCode_READ_ERROR_REVERTED ReadErrorCode = 3 // destination executed the request and returned a failure (EVM revert, HTTP 4xx) + ReadErrorCode_READ_ERROR_NOT_FOUND ReadErrorCode = 4 // queried account, state, or field does not exist at the pinned point + ReadErrorCode_READ_ERROR_INVALID_RESULT ReadErrorCode = 5 // destination returned data that could not be interpreted or encoded + ReadErrorCode_READ_ERROR_REJECTED ReadErrorCode = 6 // request refused by validator policy before execution (web2 SSRF/blacklist) +) + +// Enum value maps for ReadErrorCode. +var ( + ReadErrorCode_name = map[int32]string{ + 0: "READ_ERROR_UNSPECIFIED", + 1: "READ_ERROR_INVALID_QUERY", + 2: "READ_ERROR_UNSUPPORTED", + 3: "READ_ERROR_REVERTED", + 4: "READ_ERROR_NOT_FOUND", + 5: "READ_ERROR_INVALID_RESULT", + 6: "READ_ERROR_REJECTED", + } + ReadErrorCode_value = map[string]int32{ + "READ_ERROR_UNSPECIFIED": 0, + "READ_ERROR_INVALID_QUERY": 1, + "READ_ERROR_UNSUPPORTED": 2, + "READ_ERROR_REVERTED": 3, + "READ_ERROR_NOT_FOUND": 4, + "READ_ERROR_INVALID_RESULT": 5, + "READ_ERROR_REJECTED": 6, + } +) + +func (x ReadErrorCode) Enum() *ReadErrorCode { + p := new(ReadErrorCode) + *p = x + return p +} + +func (x ReadErrorCode) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (ReadErrorCode) Descriptor() protoreflect.EnumDescriptor { + return file_ucallback_v1_types_proto_enumTypes[0].Descriptor() +} + +func (ReadErrorCode) Type() protoreflect.EnumType { + return &file_ucallback_v1_types_proto_enumTypes[0] +} + +func (x ReadErrorCode) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use ReadErrorCode.Descriptor instead. +func (ReadErrorCode) EnumDescriptor() ([]byte, []int) { + return file_ucallback_v1_types_proto_rawDescGZIP(), []int{0} +} + +type ReadStatus int32 + +const ( + ReadStatus_READ_STATUS_UNSPECIFIED ReadStatus = 0 + ReadStatus_READ_STATUS_SUCCESS ReadStatus = 1 + ReadStatus_READ_STATUS_ERROR ReadStatus = 2 +) + +// Enum value maps for ReadStatus. +var ( + ReadStatus_name = map[int32]string{ + 0: "READ_STATUS_UNSPECIFIED", + 1: "READ_STATUS_SUCCESS", + 2: "READ_STATUS_ERROR", + } + ReadStatus_value = map[string]int32{ + "READ_STATUS_UNSPECIFIED": 0, + "READ_STATUS_SUCCESS": 1, + "READ_STATUS_ERROR": 2, + } +) + +func (x ReadStatus) Enum() *ReadStatus { + p := new(ReadStatus) + *p = x + return p +} + +func (x ReadStatus) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (ReadStatus) Descriptor() protoreflect.EnumDescriptor { + return file_ucallback_v1_types_proto_enumTypes[1].Descriptor() +} + +func (ReadStatus) Type() protoreflect.EnumType { + return &file_ucallback_v1_types_proto_enumTypes[1] +} + +func (x ReadStatus) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use ReadStatus.Descriptor instead. +func (ReadStatus) EnumDescriptor() ([]byte, []int) { + return file_ucallback_v1_types_proto_rawDescGZIP(), []int{1} +} + +// UniversalReadStatus is the lifecycle state of a read request on Push Chain. +type UniversalReadStatus int32 + +const ( + UniversalReadStatus_UNIVERSAL_READ_STATUS_UNSPECIFIED UniversalReadStatus = 0 + UniversalReadStatus_UNIVERSAL_READ_STATUS_PENDING UniversalReadStatus = 1 // ingested, awaiting votes + UniversalReadStatus_UNIVERSAL_READ_STATUS_VOTING UniversalReadStatus = 2 // at least one vote, no quorum yet + UniversalReadStatus_UNIVERSAL_READ_STATUS_FULFILLED UniversalReadStatus = 3 // callback dispatched successfully + UniversalReadStatus_UNIVERSAL_READ_STATUS_EXPIRED UniversalReadStatus = 4 // expireExternalRead accepted by the contract + UniversalReadStatus_UNIVERSAL_READ_STATUS_FAILED UniversalReadStatus = 5 // quorum reached but the callback reverted + // Gave up: expireExternalRead failed MaxExpiryAttempts times and the contract + // never acknowledged the request. Distinct from EXPIRED because the contract may + // still hold it as pending — and since expireExternalRead is module-gated, no + // other caller can settle it. Requires manual intervention, the same sense as + // uexecutor's ABORTED. See error_msg on UniversalRead for the last failure. + UniversalReadStatus_UNIVERSAL_READ_STATUS_ABORTED UniversalReadStatus = 6 +) + +// Enum value maps for UniversalReadStatus. +var ( + UniversalReadStatus_name = map[int32]string{ + 0: "UNIVERSAL_READ_STATUS_UNSPECIFIED", + 1: "UNIVERSAL_READ_STATUS_PENDING", + 2: "UNIVERSAL_READ_STATUS_VOTING", + 3: "UNIVERSAL_READ_STATUS_FULFILLED", + 4: "UNIVERSAL_READ_STATUS_EXPIRED", + 5: "UNIVERSAL_READ_STATUS_FAILED", + 6: "UNIVERSAL_READ_STATUS_ABORTED", + } + UniversalReadStatus_value = map[string]int32{ + "UNIVERSAL_READ_STATUS_UNSPECIFIED": 0, + "UNIVERSAL_READ_STATUS_PENDING": 1, + "UNIVERSAL_READ_STATUS_VOTING": 2, + "UNIVERSAL_READ_STATUS_FULFILLED": 3, + "UNIVERSAL_READ_STATUS_EXPIRED": 4, + "UNIVERSAL_READ_STATUS_FAILED": 5, + "UNIVERSAL_READ_STATUS_ABORTED": 6, + } +) + +func (x UniversalReadStatus) Enum() *UniversalReadStatus { + p := new(UniversalReadStatus) + *p = x + return p +} + +func (x UniversalReadStatus) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (UniversalReadStatus) Descriptor() protoreflect.EnumDescriptor { + return file_ucallback_v1_types_proto_enumTypes[2].Descriptor() +} + +func (UniversalReadStatus) Type() protoreflect.EnumType { + return &file_ucallback_v1_types_proto_enumTypes[2] +} + +func (x UniversalReadStatus) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use UniversalReadStatus.Descriptor instead. +func (UniversalReadStatus) EnumDescriptor() ([]byte, []int) { + return file_ucallback_v1_types_proto_rawDescGZIP(), []int{2} +} + +// ReadRequest is one external read requested by an app on Push Chain. +// +// Every field is derived from the UniversalCallback.ReadRequested event, except +// created_at_height / requested_tx_hash / requested_log_index which come from the +// block the log was emitted in. +// +// NOTE: callbackGasLimit is deliberately absent. It is an argument to +// requestExternalReadSelf and is stored in the contract's _pending entry, but it is +// NOT emitted in ReadRequested. It has to be read back via getPendingRead(requestId) +// at fulfilment time, when the gas budget is actually needed. +type ReadRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + RequestId string `protobuf:"bytes,1,opt,name=request_id,json=requestId,proto3" json:"request_id,omitempty"` // uint256 requestId as 0x-prefixed hex + DestinationChain string `protobuf:"bytes,2,opt,name=destination_chain,json=destinationChain,proto3" json:"destination_chain,omitempty"` // CAIP-2, e.g. "eip155:1"; web2 uses "web2:https" + Owner []byte `protobuf:"bytes,3,opt,name=owner,proto3" json:"owner,omitempty"` // 20-byte address or 32-byte pubkey + Query []byte `protobuf:"bytes,4,opt,name=query,proto3" json:"query,omitempty"` // chain-specific envelope, abi.encode(...) + MinConfirmations uint32 `protobuf:"varint,5,opt,name=min_confirmations,json=minConfirmations,proto3" json:"min_confirmations,omitempty"` // uint16 on the contract; proto3 has no uint16 + DestinationBlockHeight uint64 `protobuf:"varint,6,opt,name=destination_block_height,json=destinationBlockHeight,proto3" json:"destination_block_height,omitempty"` // height on the destination chain; unused for web2 + ExpiryBlockHeight uint64 `protobuf:"varint,7,opt,name=expiry_block_height,json=expiryBlockHeight,proto3" json:"expiry_block_height,omitempty"` // Push Chain height at which the request expires + CreatedAtHeight uint64 `protobuf:"varint,8,opt,name=created_at_height,json=createdAtHeight,proto3" json:"created_at_height,omitempty"` // Push Chain height the request was observed at + // Bookkeeping — recorded for operators, not consumed by universal validators. + CallbackTarget string `protobuf:"bytes,9,opt,name=callback_target,json=callbackTarget,proto3" json:"callback_target,omitempty"` // the app contract the callback routes to + OriginalFunder string `protobuf:"bytes,10,opt,name=original_funder,json=originalFunder,proto3" json:"original_funder,omitempty"` // who paid the fee (the app, not the end user) + FeesDeposited string `protobuf:"bytes,11,opt,name=fees_deposited,json=feesDeposited,proto3" json:"fees_deposited,omitempty"` // total msg.value paid, uint256 decimal string + MaxFee string `protobuf:"bytes,12,opt,name=max_fee,json=maxFee,proto3" json:"max_fee,omitempty"` // uint256 as a decimal string + RequestedTxHash string `protobuf:"bytes,13,opt,name=requested_tx_hash,json=requestedTxHash,proto3" json:"requested_tx_hash,omitempty"` // Push Chain tx that emitted ReadRequested + RequestedLogIndex uint64 `protobuf:"varint,14,opt,name=requested_log_index,json=requestedLogIndex,proto3" json:"requested_log_index,omitempty"` // log index within that tx + // Fee split, taken from ReadRequested. protocol_fee is already in VaultPC by the + // time we see the log; only callback_budget is still escrowed on the contract. + ProtocolFee string `protobuf:"bytes,15,opt,name=protocol_fee,json=protocolFee,proto3" json:"protocol_fee,omitempty"` // uint256 decimal string + CallbackBudget string `protobuf:"bytes,16,opt,name=callback_budget,json=callbackBudget,proto3" json:"callback_budget,omitempty"` // uint256 decimal string — funds the callback + // Gas ceiling the app declared for its own callback. The contract caps the inner + // call at this; we size the fulfil transaction from it. + CallbackGasLimit uint64 `protobuf:"varint,17,opt,name=callback_gas_limit,json=callbackGasLimit,proto3" json:"callback_gas_limit,omitempty"` + // Where an unspent budget is refunded. From ReadSpec, not necessarily the funder. + RevertRecipient string `protobuf:"bytes,18,opt,name=revert_recipient,json=revertRecipient,proto3" json:"revert_recipient,omitempty"` +} + +func (x *ReadRequest) Reset() { + *x = ReadRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_ucallback_v1_types_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ReadRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ReadRequest) ProtoMessage() {} + +// Deprecated: Use ReadRequest.ProtoReflect.Descriptor instead. +func (*ReadRequest) Descriptor() ([]byte, []int) { + return file_ucallback_v1_types_proto_rawDescGZIP(), []int{0} +} + +func (x *ReadRequest) GetRequestId() string { + if x != nil { + return x.RequestId + } + return "" +} + +func (x *ReadRequest) GetDestinationChain() string { + if x != nil { + return x.DestinationChain + } + return "" +} + +func (x *ReadRequest) GetOwner() []byte { + if x != nil { + return x.Owner + } + return nil +} + +func (x *ReadRequest) GetQuery() []byte { + if x != nil { + return x.Query + } + return nil +} + +func (x *ReadRequest) GetMinConfirmations() uint32 { + if x != nil { + return x.MinConfirmations + } + return 0 +} + +func (x *ReadRequest) GetDestinationBlockHeight() uint64 { + if x != nil { + return x.DestinationBlockHeight + } + return 0 +} + +func (x *ReadRequest) GetExpiryBlockHeight() uint64 { + if x != nil { + return x.ExpiryBlockHeight + } + return 0 +} + +func (x *ReadRequest) GetCreatedAtHeight() uint64 { + if x != nil { + return x.CreatedAtHeight + } + return 0 +} + +func (x *ReadRequest) GetCallbackTarget() string { + if x != nil { + return x.CallbackTarget + } + return "" +} + +func (x *ReadRequest) GetOriginalFunder() string { + if x != nil { + return x.OriginalFunder + } + return "" +} + +func (x *ReadRequest) GetFeesDeposited() string { + if x != nil { + return x.FeesDeposited + } + return "" +} + +func (x *ReadRequest) GetMaxFee() string { + if x != nil { + return x.MaxFee + } + return "" +} + +func (x *ReadRequest) GetRequestedTxHash() string { + if x != nil { + return x.RequestedTxHash + } + return "" +} + +func (x *ReadRequest) GetRequestedLogIndex() uint64 { + if x != nil { + return x.RequestedLogIndex + } + return 0 +} + +func (x *ReadRequest) GetProtocolFee() string { + if x != nil { + return x.ProtocolFee + } + return "" +} + +func (x *ReadRequest) GetCallbackBudget() string { + if x != nil { + return x.CallbackBudget + } + return "" +} + +func (x *ReadRequest) GetCallbackGasLimit() uint64 { + if x != nil { + return x.CallbackGasLimit + } + return 0 +} + +func (x *ReadRequest) GetRevertRecipient() string { + if x != nil { + return x.RevertRecipient + } + return "" +} + +// ReadResult is the observation a universal validator votes on. +// +// Every field here is covered by the ballot key, so they must be byte-identical +// across validators for a ballot to converge. There is deliberately no error message +// field: local error text differs per node and would prevent agreement. +type ReadResult struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Status ReadStatus `protobuf:"varint,1,opt,name=status,proto3,enum=ucallback.v1.ReadStatus" json:"status,omitempty"` + ResultData []byte `protobuf:"bytes,2,opt,name=result_data,json=resultData,proto3" json:"result_data,omitempty"` // ABI-encoded payload delivered to the app + // v2 ONLY — always empty in v1. See AggregateValue. + Aggregates []*AggregateValue `protobuf:"bytes,5,rep,name=aggregates,proto3" json:"aggregates,omitempty"` + // Why the read failed. Meaningful only when status is READ_STATUS_ERROR, and + // must be READ_ERROR_UNSPECIFIED otherwise — a SUCCESS vote carrying a code + // would hash to a different ballot than an honest SUCCESS vote and split quorum. + // + // An enum rather than free text on purpose: it participates in the ballot key, + // so it must be a value validators independently converge on. A string invites + // fmt.Sprintf("%v", err), whose text varies by RPC provider even for identical + // on-chain failures. + ErrorCode ReadErrorCode `protobuf:"varint,6,opt,name=error_code,json=errorCode,proto3,enum=ucallback.v1.ReadErrorCode" json:"error_code,omitempty"` +} + +func (x *ReadResult) Reset() { + *x = ReadResult{} + if protoimpl.UnsafeEnabled { + mi := &file_ucallback_v1_types_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ReadResult) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ReadResult) ProtoMessage() {} + +// Deprecated: Use ReadResult.ProtoReflect.Descriptor instead. +func (*ReadResult) Descriptor() ([]byte, []int) { + return file_ucallback_v1_types_proto_rawDescGZIP(), []int{1} +} + +func (x *ReadResult) GetStatus() ReadStatus { + if x != nil { + return x.Status + } + return ReadStatus_READ_STATUS_UNSPECIFIED +} + +func (x *ReadResult) GetResultData() []byte { + if x != nil { + return x.ResultData + } + return nil +} + +func (x *ReadResult) GetAggregates() []*AggregateValue { + if x != nil { + return x.Aggregates + } + return nil +} + +func (x *ReadResult) GetErrorCode() ReadErrorCode { + if x != nil { + return x.ErrorCode + } + return ReadErrorCode_READ_ERROR_UNSPECIFIED +} + +// AggregateValue is one field the module combines across validators instead of +// requiring byte-equality on — a price, say, where honest nodes legitimately differ. +// +// NOT USED IN v1. The universal client rejects any extract mode other than IDENTICAL +// (externalchains/web2/read_envelope.go), so this list is always empty today. The field +// is reserved now because adding it later would change how ballots are keyed on a live +// chain, which is consensus-breaking. In v1 the ballot key covers all of fields 1-4; in +// v2 it must cover only fields 1-4 with `aggregates` EXCLUDED, so computing the key over +// "the identical subset" from the start keeps v2 purely additive. +// +// v2 ALSO REQUIRES REPLACING THE BALLOT MECHANISM, not just populating this field. +// Ballots today store a binary VoteResult{SUCCESS|FAILURE} against an ID that encodes the +// observation, so distinct observations produce distinct ballots and none reaches quorum +// when validators report different numbers. Ballots therefore cannot retain per-validator +// values, which is exactly what a median needs. v2 has to keep each validator's +// AggregateValue set in module state and reduce at quorum — the pattern x/uexecutor +// already uses for gas-price medians in keeper/chain_meta.go, which bypasses ballots for +// the same reason. +type AggregateValue struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ExtractIndex uint32 `protobuf:"varint,1,opt,name=extract_index,json=extractIndex,proto3" json:"extract_index,omitempty"` // index into the query envelope's extract list + Mode uint32 `protobuf:"varint,2,opt,name=mode,proto3" json:"mode,omitempty"` // aggregation mode; only MEDIAN is planned + Value []byte `protobuf:"bytes,3,opt,name=value,proto3" json:"value,omitempty"` // big-endian uint256/int256 +} + +func (x *AggregateValue) Reset() { + *x = AggregateValue{} + if protoimpl.UnsafeEnabled { + mi := &file_ucallback_v1_types_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AggregateValue) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AggregateValue) ProtoMessage() {} + +// Deprecated: Use AggregateValue.ProtoReflect.Descriptor instead. +func (*AggregateValue) Descriptor() ([]byte, []int) { + return file_ucallback_v1_types_proto_rawDescGZIP(), []int{2} +} + +func (x *AggregateValue) GetExtractIndex() uint32 { + if x != nil { + return x.ExtractIndex + } + return 0 +} + +func (x *AggregateValue) GetMode() uint32 { + if x != nil { + return x.Mode + } + return 0 +} + +func (x *AggregateValue) GetValue() []byte { + if x != nil { + return x.Value + } + return nil +} + +// UniversalRead is the full lifecycle record of one read request. +// +// The read-side sibling of uexecutor's UniversalTx, but deliberately not the same +// shape: a read is triggered by a Push Chain event rather than an external inbound, +// performs no external write, and settles in exactly one Push Chain transaction. +type UniversalRead struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` // requestId, same value as request.request_id + Request *ReadRequest `protobuf:"bytes,2,opt,name=request,proto3" json:"request,omitempty"` + Result *ReadResult `protobuf:"bytes,3,opt,name=result,proto3" json:"result,omitempty"` // set once the ballot finalises + Status UniversalReadStatus `protobuf:"varint,4,opt,name=status,proto3,enum=ucallback.v1.UniversalReadStatus" json:"status,omitempty"` + BallotKey string `protobuf:"bytes,5,opt,name=ballot_key,json=ballotKey,proto3" json:"ballot_key,omitempty"` + // Push Chain execution attempts — fulfilExternalCallback and expireExternalRead. + // Repeated because fulfilment can be retried and may be followed by an expiry. + PcTx []*v1.PCTx `protobuf:"bytes,6,rep,name=pc_tx,json=pcTx,proto3" json:"pc_tx,omitempty"` + // Why the chain stopped acting on this read. Populated on the ABORTED and FAILED + // paths from the EVM result, so it is identical on every node — this is our own + // execution outcome, not a validator's observation, and it never touches a ballot. + ErrorMsg string `protobuf:"bytes,7,opt,name=error_msg,json=errorMsg,proto3" json:"error_msg,omitempty"` + // How many times the sweeper has called expireExternalRead for this read. + // + // An explicit counter rather than len(pc_tx): pc_tx accumulates every EVM attempt + // on the request, including a failed fulfilment that left it in flight, so + // counting entries would silently shorten the retry budget for exactly the reads + // that already had trouble. + ExpiryAttempts uint32 `protobuf:"varint,8,opt,name=expiry_attempts,json=expiryAttempts,proto3" json:"expiry_attempts,omitempty"` +} + +func (x *UniversalRead) Reset() { + *x = UniversalRead{} + if protoimpl.UnsafeEnabled { + mi := &file_ucallback_v1_types_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UniversalRead) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UniversalRead) ProtoMessage() {} + +// Deprecated: Use UniversalRead.ProtoReflect.Descriptor instead. +func (*UniversalRead) Descriptor() ([]byte, []int) { + return file_ucallback_v1_types_proto_rawDescGZIP(), []int{3} +} + +func (x *UniversalRead) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *UniversalRead) GetRequest() *ReadRequest { + if x != nil { + return x.Request + } + return nil +} + +func (x *UniversalRead) GetResult() *ReadResult { + if x != nil { + return x.Result + } + return nil +} + +func (x *UniversalRead) GetStatus() UniversalReadStatus { + if x != nil { + return x.Status + } + return UniversalReadStatus_UNIVERSAL_READ_STATUS_UNSPECIFIED +} + +func (x *UniversalRead) GetBallotKey() string { + if x != nil { + return x.BallotKey + } + return "" +} + +func (x *UniversalRead) GetPcTx() []*v1.PCTx { + if x != nil { + return x.PcTx + } + return nil +} + +func (x *UniversalRead) GetErrorMsg() string { + if x != nil { + return x.ErrorMsg + } + return "" +} + +func (x *UniversalRead) GetExpiryAttempts() uint32 { + if x != nil { + return x.ExpiryAttempts + } + return 0 +} + +var File_ucallback_v1_types_proto protoreflect.FileDescriptor + +var file_ucallback_v1_types_proto_rawDesc = []byte{ + 0x0a, 0x18, 0x75, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x2f, 0x76, 0x31, 0x2f, 0x74, + 0x79, 0x70, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0c, 0x75, 0x63, 0x61, 0x6c, + 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x2e, 0x76, 0x31, 0x1a, 0x14, 0x67, 0x6f, 0x67, 0x6f, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x67, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x11, + 0x61, 0x6d, 0x69, 0x6e, 0x6f, 0x2f, 0x61, 0x6d, 0x69, 0x6e, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x1a, 0x18, 0x75, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x6f, 0x72, 0x2f, 0x76, 0x31, 0x2f, + 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xe1, 0x05, 0x0a, 0x0b, + 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x72, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x2b, 0x0a, 0x11, 0x64, 0x65, + 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x6f, 0x77, 0x6e, 0x65, 0x72, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x12, 0x14, 0x0a, + 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x71, 0x75, + 0x65, 0x72, 0x79, 0x12, 0x2b, 0x0a, 0x11, 0x6d, 0x69, 0x6e, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, + 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x10, + 0x6d, 0x69, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x12, 0x38, 0x0a, 0x18, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, + 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x16, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x2e, 0x0a, 0x13, 0x65, 0x78, + 0x70, 0x69, 0x72, 0x79, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x68, 0x65, 0x69, 0x67, 0x68, + 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, 0x52, 0x11, 0x65, 0x78, 0x70, 0x69, 0x72, 0x79, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x2a, 0x0a, 0x11, 0x63, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x5f, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, + 0x08, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, + 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x27, 0x0a, 0x0f, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, + 0x63, 0x6b, 0x5f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0e, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, + 0x27, 0x0a, 0x0f, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x5f, 0x66, 0x75, 0x6e, 0x64, + 0x65, 0x72, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, + 0x61, 0x6c, 0x46, 0x75, 0x6e, 0x64, 0x65, 0x72, 0x12, 0x25, 0x0a, 0x0e, 0x66, 0x65, 0x65, 0x73, + 0x5f, 0x64, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x65, 0x64, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0d, 0x66, 0x65, 0x65, 0x73, 0x44, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x65, 0x64, 0x12, + 0x17, 0x0a, 0x07, 0x6d, 0x61, 0x78, 0x5f, 0x66, 0x65, 0x65, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x06, 0x6d, 0x61, 0x78, 0x46, 0x65, 0x65, 0x12, 0x2a, 0x0a, 0x11, 0x72, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x65, 0x64, 0x5f, 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x0d, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x65, 0x64, 0x54, 0x78, + 0x48, 0x61, 0x73, 0x68, 0x12, 0x2e, 0x0a, 0x13, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x65, + 0x64, 0x5f, 0x6c, 0x6f, 0x67, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x0e, 0x20, 0x01, 0x28, + 0x04, 0x52, 0x11, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x65, 0x64, 0x4c, 0x6f, 0x67, 0x49, + 0x6e, 0x64, 0x65, 0x78, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, + 0x5f, 0x66, 0x65, 0x65, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x63, 0x6f, 0x6c, 0x46, 0x65, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x63, 0x61, 0x6c, 0x6c, 0x62, + 0x61, 0x63, 0x6b, 0x5f, 0x62, 0x75, 0x64, 0x67, 0x65, 0x74, 0x18, 0x10, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0e, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x42, 0x75, 0x64, 0x67, 0x65, 0x74, + 0x12, 0x2c, 0x0a, 0x12, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x5f, 0x67, 0x61, 0x73, + 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x11, 0x20, 0x01, 0x28, 0x04, 0x52, 0x10, 0x63, 0x61, + 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x47, 0x61, 0x73, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x29, + 0x0a, 0x10, 0x72, 0x65, 0x76, 0x65, 0x72, 0x74, 0x5f, 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, + 0x6e, 0x74, 0x18, 0x12, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x72, 0x65, 0x76, 0x65, 0x72, 0x74, + 0x52, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x3a, 0x04, 0xe8, 0xa0, 0x1f, 0x01, 0x22, + 0x97, 0x02, 0x0a, 0x0a, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x30, + 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x18, + 0x2e, 0x75, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, + 0x61, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x12, 0x1f, 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x44, 0x61, 0x74, + 0x61, 0x12, 0x3c, 0x0a, 0x0a, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x73, 0x18, + 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x75, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, + 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x56, 0x61, + 0x6c, 0x75, 0x65, 0x52, 0x0a, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x73, 0x12, + 0x3a, 0x0a, 0x0a, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x75, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x2e, + 0x76, 0x31, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x43, 0x6f, 0x64, 0x65, + 0x52, 0x09, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x3a, 0x04, 0xe8, 0xa0, 0x1f, + 0x01, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, 0x52, 0x15, 0x6f, + 0x62, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x68, 0x65, + 0x69, 0x67, 0x68, 0x74, 0x52, 0x13, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x5f, 0x62, + 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x22, 0x65, 0x0a, 0x0e, 0x41, 0x67, 0x67, + 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x65, + 0x78, 0x74, 0x72, 0x61, 0x63, 0x74, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0d, 0x52, 0x0c, 0x65, 0x78, 0x74, 0x72, 0x61, 0x63, 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, + 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, + 0x6d, 0x6f, 0x64, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x04, 0xe8, 0xa0, 0x1f, 0x01, + 0x22, 0xf2, 0x02, 0x0a, 0x0d, 0x55, 0x6e, 0x69, 0x76, 0x65, 0x72, 0x73, 0x61, 0x6c, 0x52, 0x65, + 0x61, 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, + 0x69, 0x64, 0x12, 0x33, 0x0a, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x75, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x2e, + 0x76, 0x31, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x07, + 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x30, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, + 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x75, 0x63, 0x61, 0x6c, 0x6c, 0x62, + 0x61, 0x63, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, + 0x74, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x39, 0x0a, 0x06, 0x73, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x21, 0x2e, 0x75, 0x63, 0x61, 0x6c, + 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x6e, 0x69, 0x76, 0x65, 0x72, 0x73, + 0x61, 0x6c, 0x52, 0x65, 0x61, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x61, 0x6c, 0x6c, 0x6f, 0x74, 0x5f, 0x6b, + 0x65, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x62, 0x61, 0x6c, 0x6c, 0x6f, 0x74, + 0x4b, 0x65, 0x79, 0x12, 0x27, 0x0a, 0x05, 0x70, 0x63, 0x5f, 0x74, 0x78, 0x18, 0x06, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x75, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x6f, 0x72, 0x2e, 0x76, + 0x31, 0x2e, 0x50, 0x43, 0x54, 0x78, 0x52, 0x04, 0x70, 0x63, 0x54, 0x78, 0x12, 0x1b, 0x0a, 0x09, + 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x6d, 0x73, 0x67, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x08, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x73, 0x67, 0x12, 0x27, 0x0a, 0x0f, 0x65, 0x78, 0x70, + 0x69, 0x72, 0x79, 0x5f, 0x61, 0x74, 0x74, 0x65, 0x6d, 0x70, 0x74, 0x73, 0x18, 0x08, 0x20, 0x01, + 0x28, 0x0d, 0x52, 0x0e, 0x65, 0x78, 0x70, 0x69, 0x72, 0x79, 0x41, 0x74, 0x74, 0x65, 0x6d, 0x70, + 0x74, 0x73, 0x3a, 0x21, 0xe8, 0xa0, 0x1f, 0x01, 0x8a, 0xe7, 0xb0, 0x2a, 0x18, 0x75, 0x63, 0x61, + 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x2f, 0x75, 0x6e, 0x69, 0x76, 0x65, 0x72, 0x73, 0x61, 0x6c, + 0x5f, 0x72, 0x65, 0x61, 0x64, 0x2a, 0xd0, 0x01, 0x0a, 0x0d, 0x52, 0x65, 0x61, 0x64, 0x45, 0x72, + 0x72, 0x6f, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x1a, 0x0a, 0x16, 0x52, 0x45, 0x41, 0x44, 0x5f, + 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, + 0x44, 0x10, 0x00, 0x12, 0x1c, 0x0a, 0x18, 0x52, 0x45, 0x41, 0x44, 0x5f, 0x45, 0x52, 0x52, 0x4f, + 0x52, 0x5f, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x5f, 0x51, 0x55, 0x45, 0x52, 0x59, 0x10, + 0x01, 0x12, 0x1a, 0x0a, 0x16, 0x52, 0x45, 0x41, 0x44, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, + 0x55, 0x4e, 0x53, 0x55, 0x50, 0x50, 0x4f, 0x52, 0x54, 0x45, 0x44, 0x10, 0x02, 0x12, 0x17, 0x0a, + 0x13, 0x52, 0x45, 0x41, 0x44, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x52, 0x45, 0x56, 0x45, + 0x52, 0x54, 0x45, 0x44, 0x10, 0x03, 0x12, 0x18, 0x0a, 0x14, 0x52, 0x45, 0x41, 0x44, 0x5f, 0x45, + 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x4e, 0x4f, 0x54, 0x5f, 0x46, 0x4f, 0x55, 0x4e, 0x44, 0x10, 0x04, + 0x12, 0x1d, 0x0a, 0x19, 0x52, 0x45, 0x41, 0x44, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x49, + 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x5f, 0x52, 0x45, 0x53, 0x55, 0x4c, 0x54, 0x10, 0x05, 0x12, + 0x17, 0x0a, 0x13, 0x52, 0x45, 0x41, 0x44, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x52, 0x45, + 0x4a, 0x45, 0x43, 0x54, 0x45, 0x44, 0x10, 0x06, 0x2a, 0x5f, 0x0a, 0x0a, 0x52, 0x65, 0x61, 0x64, + 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1b, 0x0a, 0x17, 0x52, 0x45, 0x41, 0x44, 0x5f, 0x53, + 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, + 0x44, 0x10, 0x00, 0x12, 0x17, 0x0a, 0x13, 0x52, 0x45, 0x41, 0x44, 0x5f, 0x53, 0x54, 0x41, 0x54, + 0x55, 0x53, 0x5f, 0x53, 0x55, 0x43, 0x43, 0x45, 0x53, 0x53, 0x10, 0x01, 0x12, 0x15, 0x0a, 0x11, + 0x52, 0x45, 0x41, 0x44, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x45, 0x52, 0x52, 0x4f, + 0x52, 0x10, 0x02, 0x1a, 0x04, 0xa8, 0xa4, 0x1e, 0x01, 0x2a, 0x94, 0x02, 0x0a, 0x13, 0x55, 0x6e, + 0x69, 0x76, 0x65, 0x72, 0x73, 0x61, 0x6c, 0x52, 0x65, 0x61, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x12, 0x25, 0x0a, 0x21, 0x55, 0x4e, 0x49, 0x56, 0x45, 0x52, 0x53, 0x41, 0x4c, 0x5f, 0x52, + 0x45, 0x41, 0x44, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, + 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x21, 0x0a, 0x1d, 0x55, 0x4e, 0x49, 0x56, + 0x45, 0x52, 0x53, 0x41, 0x4c, 0x5f, 0x52, 0x45, 0x41, 0x44, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, + 0x53, 0x5f, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x20, 0x0a, 0x1c, 0x55, + 0x4e, 0x49, 0x56, 0x45, 0x52, 0x53, 0x41, 0x4c, 0x5f, 0x52, 0x45, 0x41, 0x44, 0x5f, 0x53, 0x54, + 0x41, 0x54, 0x55, 0x53, 0x5f, 0x56, 0x4f, 0x54, 0x49, 0x4e, 0x47, 0x10, 0x02, 0x12, 0x23, 0x0a, + 0x1f, 0x55, 0x4e, 0x49, 0x56, 0x45, 0x52, 0x53, 0x41, 0x4c, 0x5f, 0x52, 0x45, 0x41, 0x44, 0x5f, + 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x46, 0x55, 0x4c, 0x46, 0x49, 0x4c, 0x4c, 0x45, 0x44, + 0x10, 0x03, 0x12, 0x21, 0x0a, 0x1d, 0x55, 0x4e, 0x49, 0x56, 0x45, 0x52, 0x53, 0x41, 0x4c, 0x5f, + 0x52, 0x45, 0x41, 0x44, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x45, 0x58, 0x50, 0x49, + 0x52, 0x45, 0x44, 0x10, 0x04, 0x12, 0x20, 0x0a, 0x1c, 0x55, 0x4e, 0x49, 0x56, 0x45, 0x52, 0x53, + 0x41, 0x4c, 0x5f, 0x52, 0x45, 0x41, 0x44, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x46, + 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0x05, 0x12, 0x21, 0x0a, 0x1d, 0x55, 0x4e, 0x49, 0x56, 0x45, + 0x52, 0x53, 0x41, 0x4c, 0x5f, 0x52, 0x45, 0x41, 0x44, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, + 0x5f, 0x41, 0x42, 0x4f, 0x52, 0x54, 0x45, 0x44, 0x10, 0x06, 0x1a, 0x04, 0xa8, 0xa4, 0x1e, 0x01, + 0x42, 0xb2, 0x01, 0x0a, 0x10, 0x63, 0x6f, 0x6d, 0x2e, 0x75, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, + 0x63, 0x6b, 0x2e, 0x76, 0x31, 0x42, 0x0a, 0x54, 0x79, 0x70, 0x65, 0x73, 0x50, 0x72, 0x6f, 0x74, + 0x6f, 0x50, 0x01, 0x5a, 0x41, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, + 0x70, 0x75, 0x73, 0x68, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x2f, 0x70, 0x75, 0x73, 0x68, 0x2d, 0x63, + 0x68, 0x61, 0x69, 0x6e, 0x2d, 0x6e, 0x6f, 0x64, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x75, 0x63, + 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x2f, 0x76, 0x31, 0x3b, 0x75, 0x63, 0x61, 0x6c, 0x6c, + 0x62, 0x61, 0x63, 0x6b, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x55, 0x58, 0x58, 0xaa, 0x02, 0x0c, 0x55, + 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x0c, 0x55, 0x63, + 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x18, 0x55, 0x63, 0x61, + 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, + 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0d, 0x55, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, + 0x6b, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_ucallback_v1_types_proto_rawDescOnce sync.Once + file_ucallback_v1_types_proto_rawDescData = file_ucallback_v1_types_proto_rawDesc +) + +func file_ucallback_v1_types_proto_rawDescGZIP() []byte { + file_ucallback_v1_types_proto_rawDescOnce.Do(func() { + file_ucallback_v1_types_proto_rawDescData = protoimpl.X.CompressGZIP(file_ucallback_v1_types_proto_rawDescData) + }) + return file_ucallback_v1_types_proto_rawDescData +} + +var file_ucallback_v1_types_proto_enumTypes = make([]protoimpl.EnumInfo, 3) +var file_ucallback_v1_types_proto_msgTypes = make([]protoimpl.MessageInfo, 4) +var file_ucallback_v1_types_proto_goTypes = []interface{}{ + (ReadErrorCode)(0), // 0: ucallback.v1.ReadErrorCode + (ReadStatus)(0), // 1: ucallback.v1.ReadStatus + (UniversalReadStatus)(0), // 2: ucallback.v1.UniversalReadStatus + (*ReadRequest)(nil), // 3: ucallback.v1.ReadRequest + (*ReadResult)(nil), // 4: ucallback.v1.ReadResult + (*AggregateValue)(nil), // 5: ucallback.v1.AggregateValue + (*UniversalRead)(nil), // 6: ucallback.v1.UniversalRead + (*v1.PCTx)(nil), // 7: uexecutor.v1.PCTx +} +var file_ucallback_v1_types_proto_depIdxs = []int32{ + 1, // 0: ucallback.v1.ReadResult.status:type_name -> ucallback.v1.ReadStatus + 5, // 1: ucallback.v1.ReadResult.aggregates:type_name -> ucallback.v1.AggregateValue + 0, // 2: ucallback.v1.ReadResult.error_code:type_name -> ucallback.v1.ReadErrorCode + 3, // 3: ucallback.v1.UniversalRead.request:type_name -> ucallback.v1.ReadRequest + 4, // 4: ucallback.v1.UniversalRead.result:type_name -> ucallback.v1.ReadResult + 2, // 5: ucallback.v1.UniversalRead.status:type_name -> ucallback.v1.UniversalReadStatus + 7, // 6: ucallback.v1.UniversalRead.pc_tx:type_name -> uexecutor.v1.PCTx + 7, // [7:7] is the sub-list for method output_type + 7, // [7:7] is the sub-list for method input_type + 7, // [7:7] is the sub-list for extension type_name + 7, // [7:7] is the sub-list for extension extendee + 0, // [0:7] is the sub-list for field type_name +} + +func init() { file_ucallback_v1_types_proto_init() } +func file_ucallback_v1_types_proto_init() { + if File_ucallback_v1_types_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_ucallback_v1_types_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ReadRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ucallback_v1_types_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ReadResult); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ucallback_v1_types_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AggregateValue); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ucallback_v1_types_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UniversalRead); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_ucallback_v1_types_proto_rawDesc, + NumEnums: 3, + NumMessages: 4, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_ucallback_v1_types_proto_goTypes, + DependencyIndexes: file_ucallback_v1_types_proto_depIdxs, + EnumInfos: file_ucallback_v1_types_proto_enumTypes, + MessageInfos: file_ucallback_v1_types_proto_msgTypes, + }.Build() + File_ucallback_v1_types_proto = out.File + file_ucallback_v1_types_proto_rawDesc = nil + file_ucallback_v1_types_proto_goTypes = nil + file_ucallback_v1_types_proto_depIdxs = nil +} diff --git a/api/uvalidator/v1/ballot.pulsar.go b/api/uvalidator/v1/ballot.pulsar.go index 7cff2556..295b5dd8 100644 --- a/api/uvalidator/v1/ballot.pulsar.go +++ b/api/uvalidator/v1/ballot.pulsar.go @@ -1054,6 +1054,7 @@ const ( BallotObservationType_BALLOT_OBSERVATION_TYPE_OUTBOUND_TX BallotObservationType = 2 BallotObservationType_BALLOT_OBSERVATION_TYPE_TSS_KEY BallotObservationType = 3 BallotObservationType_BALLOT_OBSERVATION_TYPE_FUND_MIGRATION BallotObservationType = 4 + BallotObservationType_BALLOT_OBSERVATION_TYPE_READ_RESULT BallotObservationType = 5 ) // Enum value maps for BallotObservationType. @@ -1064,6 +1065,7 @@ var ( 2: "BALLOT_OBSERVATION_TYPE_OUTBOUND_TX", 3: "BALLOT_OBSERVATION_TYPE_TSS_KEY", 4: "BALLOT_OBSERVATION_TYPE_FUND_MIGRATION", + 5: "BALLOT_OBSERVATION_TYPE_READ_RESULT", } BallotObservationType_value = map[string]int32{ "BALLOT_OBSERVATION_TYPE_UNSPECIFIED": 0, @@ -1071,6 +1073,7 @@ var ( "BALLOT_OBSERVATION_TYPE_OUTBOUND_TX": 2, "BALLOT_OBSERVATION_TYPE_TSS_KEY": 3, "BALLOT_OBSERVATION_TYPE_FUND_MIGRATION": 4, + "BALLOT_OBSERVATION_TYPE_READ_RESULT": 5, } ) @@ -1289,7 +1292,7 @@ var file_uvalidator_v1_ballot_proto_rawDesc = []byte{ 0x54, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x52, 0x45, 0x4a, 0x45, 0x43, 0x54, 0x45, 0x44, 0x10, 0x03, 0x12, 0x19, 0x0a, 0x15, 0x42, 0x41, 0x4c, 0x4c, 0x4f, 0x54, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x45, 0x58, 0x50, 0x49, 0x52, 0x45, 0x44, 0x10, 0x04, 0x1a, 0x04, - 0xa8, 0xa4, 0x1e, 0x01, 0x2a, 0xe8, 0x01, 0x0a, 0x15, 0x42, 0x61, 0x6c, 0x6c, 0x6f, 0x74, 0x4f, + 0xa8, 0xa4, 0x1e, 0x01, 0x2a, 0x91, 0x02, 0x0a, 0x15, 0x42, 0x61, 0x6c, 0x6c, 0x6f, 0x74, 0x4f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x27, 0x0a, 0x23, 0x42, 0x41, 0x4c, 0x4c, 0x4f, 0x54, 0x5f, 0x4f, 0x42, 0x53, 0x45, 0x52, 0x56, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, @@ -1303,26 +1306,29 @@ var file_uvalidator_v1_ballot_proto_rawDesc = []byte{ 0x59, 0x50, 0x45, 0x5f, 0x54, 0x53, 0x53, 0x5f, 0x4b, 0x45, 0x59, 0x10, 0x03, 0x12, 0x2a, 0x0a, 0x26, 0x42, 0x41, 0x4c, 0x4c, 0x4f, 0x54, 0x5f, 0x4f, 0x42, 0x53, 0x45, 0x52, 0x56, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x46, 0x55, 0x4e, 0x44, 0x5f, 0x4d, 0x49, - 0x47, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x04, 0x1a, 0x04, 0xa8, 0xa4, 0x1e, 0x01, 0x2a, - 0x63, 0x0a, 0x0a, 0x56, 0x6f, 0x74, 0x65, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x1d, 0x0a, - 0x19, 0x56, 0x4f, 0x54, 0x45, 0x5f, 0x52, 0x45, 0x53, 0x55, 0x4c, 0x54, 0x5f, 0x4e, 0x4f, 0x54, - 0x5f, 0x59, 0x45, 0x54, 0x5f, 0x56, 0x4f, 0x54, 0x45, 0x44, 0x10, 0x00, 0x12, 0x17, 0x0a, 0x13, - 0x56, 0x4f, 0x54, 0x45, 0x5f, 0x52, 0x45, 0x53, 0x55, 0x4c, 0x54, 0x5f, 0x53, 0x55, 0x43, 0x43, - 0x45, 0x53, 0x53, 0x10, 0x01, 0x12, 0x17, 0x0a, 0x13, 0x56, 0x4f, 0x54, 0x45, 0x5f, 0x52, 0x45, - 0x53, 0x55, 0x4c, 0x54, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x10, 0x02, 0x1a, 0x04, - 0xa8, 0xa4, 0x1e, 0x01, 0x42, 0xba, 0x01, 0x0a, 0x11, 0x63, 0x6f, 0x6d, 0x2e, 0x75, 0x76, 0x61, - 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x2e, 0x76, 0x31, 0x42, 0x0b, 0x42, 0x61, 0x6c, 0x6c, - 0x6f, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x43, 0x67, 0x69, 0x74, 0x68, 0x75, - 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x75, 0x73, 0x68, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x2f, - 0x70, 0x75, 0x73, 0x68, 0x2d, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x2d, 0x6e, 0x6f, 0x64, 0x65, 0x2f, - 0x61, 0x70, 0x69, 0x2f, 0x75, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x2f, 0x76, - 0x31, 0x3b, 0x75, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x76, 0x31, 0xa2, 0x02, - 0x03, 0x55, 0x58, 0x58, 0xaa, 0x02, 0x0d, 0x55, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, - 0x72, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x0d, 0x55, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, - 0x72, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x19, 0x55, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, - 0x72, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, - 0xea, 0x02, 0x0e, 0x55, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x3a, 0x3a, 0x56, - 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x47, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x04, 0x12, 0x27, 0x0a, 0x23, 0x42, 0x41, 0x4c, + 0x4c, 0x4f, 0x54, 0x5f, 0x4f, 0x42, 0x53, 0x45, 0x52, 0x56, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, + 0x54, 0x59, 0x50, 0x45, 0x5f, 0x52, 0x45, 0x41, 0x44, 0x5f, 0x52, 0x45, 0x53, 0x55, 0x4c, 0x54, + 0x10, 0x05, 0x1a, 0x04, 0xa8, 0xa4, 0x1e, 0x01, 0x2a, 0x63, 0x0a, 0x0a, 0x56, 0x6f, 0x74, 0x65, + 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x1d, 0x0a, 0x19, 0x56, 0x4f, 0x54, 0x45, 0x5f, 0x52, + 0x45, 0x53, 0x55, 0x4c, 0x54, 0x5f, 0x4e, 0x4f, 0x54, 0x5f, 0x59, 0x45, 0x54, 0x5f, 0x56, 0x4f, + 0x54, 0x45, 0x44, 0x10, 0x00, 0x12, 0x17, 0x0a, 0x13, 0x56, 0x4f, 0x54, 0x45, 0x5f, 0x52, 0x45, + 0x53, 0x55, 0x4c, 0x54, 0x5f, 0x53, 0x55, 0x43, 0x43, 0x45, 0x53, 0x53, 0x10, 0x01, 0x12, 0x17, + 0x0a, 0x13, 0x56, 0x4f, 0x54, 0x45, 0x5f, 0x52, 0x45, 0x53, 0x55, 0x4c, 0x54, 0x5f, 0x46, 0x41, + 0x49, 0x4c, 0x55, 0x52, 0x45, 0x10, 0x02, 0x1a, 0x04, 0xa8, 0xa4, 0x1e, 0x01, 0x42, 0xba, 0x01, + 0x0a, 0x11, 0x63, 0x6f, 0x6d, 0x2e, 0x75, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, + 0x2e, 0x76, 0x31, 0x42, 0x0b, 0x42, 0x61, 0x6c, 0x6c, 0x6f, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, + 0x50, 0x01, 0x5a, 0x43, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, + 0x75, 0x73, 0x68, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x2f, 0x70, 0x75, 0x73, 0x68, 0x2d, 0x63, 0x68, + 0x61, 0x69, 0x6e, 0x2d, 0x6e, 0x6f, 0x64, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x75, 0x76, 0x61, + 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x2f, 0x76, 0x31, 0x3b, 0x75, 0x76, 0x61, 0x6c, 0x69, + 0x64, 0x61, 0x74, 0x6f, 0x72, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x55, 0x58, 0x58, 0xaa, 0x02, 0x0d, + 0x55, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x0d, + 0x55, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x19, + 0x55, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, + 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0e, 0x55, 0x76, 0x61, 0x6c, + 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x33, } var ( diff --git a/app/app.go b/app/app.go index 751096f6..31143bbc 100755 --- a/app/app.go +++ b/app/app.go @@ -54,8 +54,8 @@ import ( "github.com/cosmos/cosmos-sdk/server/config" servertypes "github.com/cosmos/cosmos-sdk/server/types" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/module" sdkmempool "github.com/cosmos/cosmos-sdk/types/mempool" + "github.com/cosmos/cosmos-sdk/types/module" "github.com/cosmos/cosmos-sdk/types/msgservice" signingtype "github.com/cosmos/cosmos-sdk/types/tx/signing" "github.com/cosmos/cosmos-sdk/version" @@ -108,9 +108,9 @@ import ( stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" cosmosevmante "github.com/cosmos/evm/ante" + antetypes "github.com/cosmos/evm/ante/types" cosmosevmencoding "github.com/cosmos/evm/encoding" srvflags "github.com/cosmos/evm/server/flags" - antetypes "github.com/cosmos/evm/ante/types" cosmosevmutils "github.com/cosmos/evm/utils" "github.com/cosmos/evm/x/erc20" erc20keeper "github.com/cosmos/evm/x/erc20/keeper" @@ -119,7 +119,6 @@ import ( feemarketkeeper "github.com/cosmos/evm/x/feemarket/keeper" feemarkettypes "github.com/cosmos/evm/x/feemarket/types" "github.com/cosmos/evm/x/vm" - // _ "github.com/ethereum/go-ethereum/core/tracers/js" // _ "github.com/ethereum/go-ethereum/core/tracers/native" evmkeeper "github.com/cosmos/evm/x/vm/keeper" @@ -153,14 +152,16 @@ import ( ibcexported "github.com/cosmos/ibc-go/v10/modules/core/exported" ibckeeper "github.com/cosmos/ibc-go/v10/modules/core/keeper" ibctm "github.com/cosmos/ibc-go/v10/modules/light-clients/07-tendermint" - // "github.com/ethereum/go-ethereum/core/vm" + ibccallbacks "github.com/cosmos/ibc-go/v10/modules/apps/callbacks" "github.com/ethereum/go-ethereum/common" cosmoscorevm "github.com/ethereum/go-ethereum/core/vm" chainante "github.com/pushchain/push-chain-node/app/ante" - usigverifierprecompile "github.com/pushchain/push-chain-node/precompiles/usigverifier" pushtypes "github.com/pushchain/push-chain-node/types" + ucallback "github.com/pushchain/push-chain-node/x/ucallback" + ucallbackkeeper "github.com/pushchain/push-chain-node/x/ucallback/keeper" + ucallbacktypes "github.com/pushchain/push-chain-node/x/ucallback/types" uexecutor "github.com/pushchain/push-chain-node/x/uexecutor" uexecutorkeeper "github.com/pushchain/push-chain-node/x/uexecutor/keeper" uexecutortypes "github.com/pushchain/push-chain-node/x/uexecutor/types" @@ -178,8 +179,6 @@ import ( tokenfactorybindings "github.com/strangelove-ventures/tokenfactory/x/tokenfactory/bindings" tokenfactorykeeper "github.com/strangelove-ventures/tokenfactory/x/tokenfactory/keeper" tokenfactorytypes "github.com/strangelove-ventures/tokenfactory/x/tokenfactory/types" - - ibccallbacks "github.com/cosmos/ibc-go/v10/modules/apps/callbacks" ) const ( @@ -209,7 +208,7 @@ type authKeeperEVMWrapper struct { authkeeper.AccountKeeper } -func (w authKeeperEVMWrapper) UnorderedTransactionsEnabled() bool { return false } +func (w authKeeperEVMWrapper) UnorderedTransactionsEnabled() bool { return false } func (w authKeeperEVMWrapper) RemoveExpiredUnorderedNonces(_ sdk.Context) error { return nil } func (w authKeeperEVMWrapper) TryAddUnorderedNonce(_ sdk.Context, _ []byte, _ time.Time) error { return nil @@ -267,6 +266,7 @@ var maccPerms = map[string][]string{ erc20types.ModuleName: {authtypes.Minter, authtypes.Burner}, uexecutortypes.ModuleName: {authtypes.Minter, authtypes.Burner}, uvalidatortypes.ModuleName: nil, + ucallbacktypes.ModuleName: {authtypes.Burner}, // burns spent callback gas } var ( @@ -286,11 +286,11 @@ type PacketDataUnmarshaler interface { // ChainApp extended ABCI application type ChainApp struct { *baseapp.BaseApp - legacyAmino *codec.LegacyAmino - appCodec codec.Codec - txConfig client.TxConfig - interfaceRegistry types.InterfaceRegistry - clientCtx client.Context + legacyAmino *codec.LegacyAmino + appCodec codec.Codec + txConfig client.TxConfig + interfaceRegistry types.InterfaceRegistry + clientCtx client.Context pendingTxListeners []func(common.Hash) // keys to access the substores @@ -332,11 +332,12 @@ type ChainApp struct { EVMKeeper *evmkeeper.Keeper Erc20Keeper erc20keeper.Keeper - ScopedWasmKeeper capabilitykeeper.ScopedKeeper - UexecutorKeeper uexecutorkeeper.Keeper - UregistryKeeper uregistrykeeper.Keeper - UvalidatorKeeper uvalidatorkeeper.Keeper - UtssKeeper utsskeeper.Keeper + ScopedWasmKeeper capabilitykeeper.ScopedKeeper + UexecutorKeeper uexecutorkeeper.Keeper + UregistryKeeper uregistrykeeper.Keeper + UvalidatorKeeper uvalidatorkeeper.Keeper + UtssKeeper utsskeeper.Keeper + UcallbackKeeper ucallbackkeeper.Keeper // the module manager ModuleManager *module.Manager @@ -451,6 +452,7 @@ func NewChainApp( uregistrytypes.StoreKey, uvalidatortypes.StoreKey, utsstypes.StoreKey, + ucallbacktypes.StoreKey, ) tkeys := storetypes.NewTransientStoreKeys( @@ -744,6 +746,25 @@ func NewChainApp( &app.UvalidatorKeeper, ) + // Create the ucallback Keeper. + // + // Constructed here, after app.EVMKeeper and app.FeeMarketKeeper exist, rather + // than earlier with the other keepers. app.EVMKeeper is a *evmkeeper.Keeper: + // passing it before line ~718 hands over a nil pointer that still satisfies the + // interface, so every DerivedEVMCall panics on the first fulfilment instead of + // failing at startup. UvalidatorKeeper is still built below, hence the pointer. + app.UcallbackKeeper = ucallbackkeeper.NewKeeper( + appCodec, + runtime.NewKVStoreService(keys[ucallbacktypes.StoreKey]), + logger, + authtypes.NewModuleAddress(govtypes.ModuleName).String(), + &app.UvalidatorKeeper, + app.EVMKeeper, + app.AccountKeeper, + app.BankKeeper, + app.FeeMarketKeeper, + ) + // Create the uvalidator Keeper app.UvalidatorKeeper = uvalidatorkeeper.NewKeeper( appCodec, @@ -779,7 +800,10 @@ func NewChainApp( app.UtssKeeper.Hooks(), uexecutorkeeper.NewUValidatorHooks(app.UexecutorKeeper), ), - Ballot: uexecutorkeeper.NewBallotHooks(app.UexecutorKeeper), + Ballot: uvalidatorkeeper.NewMultiBallotHooks( + uexecutorkeeper.NewBallotHooks(app.UexecutorKeeper), + ucallbackkeeper.NewBallotHooks(app.UcallbackKeeper), + ), }) // NOTE: stakingKeeper above is passed by reference, so it picks up these hooks. @@ -791,7 +815,13 @@ func NewChainApp( ), ) - app.EVMKeeper.SetHooks(uexecutorkeeper.NewEVMHooks(app.UexecutorKeeper)) + // SetHooks panics if called twice, so every EVM post-tx consumer registers + // here. Hooks run in order and share a transaction: an error from any one of + // them reverts the whole EVM tx, including the work earlier hooks did. + app.EVMKeeper.SetHooks(evmkeeper.NewMultiEvmHooks( + uexecutorkeeper.NewEVMHooks(app.UexecutorKeeper), + ucallbackkeeper.NewEVMHooks(app.UcallbackKeeper), + )) // NOTE: we are adding all available EVM extensions. // Not all of them need to be enabled, which can be configured on a per-chain basis. @@ -867,7 +897,7 @@ func NewChainApp( app.TransferKeeper = ibctransferkeeper.NewKeeper( appCodec, runtime.NewKVStoreService(keys[ibctransfertypes.StoreKey]), - nil, // legacySubspace (no params subspace) + nil, // legacySubspace (no params subspace) app.RatelimitKeeper, // ICS4Wrapper //app.IBCFeeKeeper, app.IBCKeeper.ChannelKeeper, @@ -1070,6 +1100,7 @@ func NewChainApp( uregistry.NewAppModule(appCodec, app.UregistryKeeper, app.EVMKeeper), uvalidator.NewAppModule(appCodec, app.UvalidatorKeeper, app.BankKeeper, app.AccountKeeper, app.DistrKeeper, app.StakingKeeper, app.SlashingKeeper, &app.UtssKeeper), utss.NewAppModule(appCodec, app.UtssKeeper, app.UvalidatorKeeper), + ucallback.NewAppModule(appCodec, app.UcallbackKeeper), ) // BasicModuleManager defines the module BasicManager is in charge of setting up basic, @@ -1120,6 +1151,7 @@ func NewChainApp( uexecutortypes.ModuleName, uregistrytypes.ModuleName, utsstypes.ModuleName, + ucallbacktypes.ModuleName, ) app.ModuleManager.SetOrderEndBlockers( @@ -1143,6 +1175,7 @@ func NewChainApp( uregistrytypes.ModuleName, uvalidatortypes.ModuleName, utsstypes.ModuleName, + ucallbacktypes.ModuleName, ) // NOTE: The genutils module must occur after staking so that pools are @@ -1193,6 +1226,7 @@ func NewChainApp( uregistrytypes.ModuleName, uvalidatortypes.ModuleName, utsstypes.ModuleName, + ucallbacktypes.ModuleName, } app.ModuleManager.SetOrderInitGenesis(genesisModuleOrder...) app.ModuleManager.SetOrderExportGenesis(genesisModuleOrder...) @@ -1606,6 +1640,9 @@ func BlockedAddresses() map[string]bool { // allow the following addresses to receive funds delete(blockedAddrs, authtypes.NewModuleAddress(govtypes.ModuleName).String()) + // x/ucallback receives the consumed callback budget out of UniversalCallback + // before burning it, so it must not be blocked from receiving. + delete(blockedAddrs, authtypes.NewModuleAddress(ucallbacktypes.ModuleName).String()) blockedPrecompilesHex := evmtypes.AvailableStaticPrecompiles for _, addr := range cosmoscorevm.PrecompiledAddressesBerlin { @@ -1654,6 +1691,7 @@ func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino paramsKeeper.Subspace(uregistrytypes.ModuleName) paramsKeeper.Subspace(uvalidatortypes.ModuleName) paramsKeeper.Subspace(utsstypes.ModuleName) + paramsKeeper.Subspace(ucallbacktypes.ModuleName) return paramsKeeper } diff --git a/proto/ucallback/module/v1/module.proto b/proto/ucallback/module/v1/module.proto new file mode 100755 index 00000000..09ef40ac --- /dev/null +++ b/proto/ucallback/module/v1/module.proto @@ -0,0 +1,13 @@ +syntax = "proto3"; + +package ucallback.module.v1; + +import "cosmos/app/v1alpha1/module.proto"; + +// Module is the app config object of the module. +// Learn more: https://docs.cosmos.network/main/building-modules/depinject +message Module { + option (cosmos.app.v1alpha1.module) = { + go_import : "github.com/pushchain/push-chain-node" + }; +} \ No newline at end of file diff --git a/proto/ucallback/v1/genesis.proto b/proto/ucallback/v1/genesis.proto new file mode 100755 index 00000000..fdce3ca4 --- /dev/null +++ b/proto/ucallback/v1/genesis.proto @@ -0,0 +1,44 @@ +syntax = "proto3"; +package ucallback.v1; + +import "gogoproto/gogo.proto"; +import "amino/amino.proto"; +import "ucallback/v1/types.proto"; + +option go_package = "github.com/pushchain/push-chain-node/x/ucallback/types"; + +// GenesisState defines the module genesis state +message GenesisState { + // Params defines all the parameters of the module. + Params params = 1 [(gogoproto.nullable) = false]; + + // universal_reads are key-value pairs from the UniversalReads map. + // + // Only the canonical records are exported. PendingByExpiry and ReadsByTxHash + // are indexes derived from these, and are rebuilt during InitGenesis rather + // than exported — so they cannot be imported out of sync with the records they + // point at. + repeated UniversalReadEntry universal_reads = 2 [(gogoproto.nullable) = false]; + + // module_account_nonce is the EVM nonce of the x/ucallback module account. + // + // Must round-trip through genesis: it is the nonce of a real EVM account, and + // exporting state without it would make every module call after an import reuse + // nonces the chain had already consumed. + uint64 module_account_nonce = 3; +} + +// UniversalReadEntry is one key-value pair from the UniversalReads map. +message UniversalReadEntry { + string key = 1; + UniversalRead value = 2 [(gogoproto.nullable) = false]; +} + +// Params defines the set of module parameters. +message Params { + option (amino.name) = "ucallback/params"; + option (gogoproto.equal) = true; + option (gogoproto.goproto_stringer) = false; + + bool some_value = 2; +} \ No newline at end of file diff --git a/proto/ucallback/v1/query.proto b/proto/ucallback/v1/query.proto new file mode 100755 index 00000000..f3c449cd --- /dev/null +++ b/proto/ucallback/v1/query.proto @@ -0,0 +1,90 @@ +syntax = "proto3"; +package ucallback.v1; + +import "gogoproto/gogo.proto"; +import "google/api/annotations.proto"; +import "cosmos/base/query/v1beta1/pagination.proto"; +import "ucallback/v1/genesis.proto"; +import "ucallback/v1/types.proto"; + +option go_package = "github.com/pushchain/push-chain-node/x/ucallback/types"; + +// Query provides defines the gRPC querier service. +service Query { + // Params queries all parameters of the module. + rpc Params(QueryParamsRequest) returns (QueryParamsResponse) { + option (google.api.http).get = "/ucallback/v1/params"; + } + + // AllPendingReadRequests lists read requests still awaiting an observation. + // This is the endpoint universal validators poll. + rpc AllPendingReadRequests(QueryAllPendingReadRequestsRequest) returns (QueryAllPendingReadRequestsResponse) { + option (google.api.http).get = "/ucallback/v1/pending_read_requests"; + } + + // UniversalRead returns one read by request id, at any point in its lifecycle. + rpc UniversalRead(QueryUniversalReadRequest) returns (QueryUniversalReadResponse) { + option (google.api.http).get = "/ucallback/v1/universal_reads/{request_id}"; + } + + // AllAbortedReadRequests lists reads the chain gave up on. These need manual + // intervention: the contract may still hold them as pending and the funder's + // refund is unsettled. + rpc AllAbortedReadRequests(QueryAllAbortedReadRequestsRequest) returns (QueryAllAbortedReadRequestsResponse) { + option (google.api.http).get = "/ucallback/v1/aborted_read_requests"; + } + + // ReadsByTxHash returns every read requested by one Push transaction. A single + // transaction can emit several ReadRequested logs; this reassembles that batch. + rpc ReadsByTx(QueryReadsByTxRequest) returns (QueryReadsByTxResponse) { + option (google.api.http).get = "/ucallback/v1/reads_by_tx/{tx_hash}"; + } +} + +// QueryParamsRequest is the request type for the Query/Params RPC method. +message QueryParamsRequest {} + +// QueryParamsResponse is the response type for the Query/Params RPC method. +message QueryParamsResponse { + // params defines the parameters of the module. + Params params = 1; +} + +message QueryAllPendingReadRequestsRequest { + cosmos.base.query.v1beta1.PageRequest pagination = 1; +} + +message QueryAllPendingReadRequestsResponse { + // Reads that are unsettled AND not yet past their expiry height. Requests past + // expiry are withheld here even before the sweeper retires them, so validators + // never take on work that can no longer be fulfilled in time. + repeated UniversalRead reads = 1 [(gogoproto.nullable) = false]; + cosmos.base.query.v1beta1.PageResponse pagination = 2; +} + +message QueryUniversalReadRequest { + string request_id = 1; +} + +message QueryUniversalReadResponse { + UniversalRead read = 1 [(gogoproto.nullable) = false]; +} + +message QueryReadsByTxRequest { + string tx_hash = 1; +} + +message QueryReadsByTxResponse { + // Every read the transaction requested, settled or not, in request-id order. + repeated UniversalRead reads = 1 [(gogoproto.nullable) = false]; +} + +message QueryAllAbortedReadRequestsRequest { + cosmos.base.query.v1beta1.PageRequest pagination = 1; +} + +message QueryAllAbortedReadRequestsResponse { + // Reads whose expiry call never landed. Each carries error_msg explaining why. + repeated UniversalRead reads = 1 [(gogoproto.nullable) = false]; + cosmos.base.query.v1beta1.PageResponse pagination = 2; +} diff --git a/proto/ucallback/v1/tx.proto b/proto/ucallback/v1/tx.proto new file mode 100755 index 00000000..1b575354 --- /dev/null +++ b/proto/ucallback/v1/tx.proto @@ -0,0 +1,104 @@ +syntax = "proto3"; +package ucallback.v1; + +import "cosmos/msg/v1/msg.proto"; +import "ucallback/v1/genesis.proto"; +import "ucallback/v1/types.proto"; +import "gogoproto/gogo.proto"; +import "cosmos_proto/cosmos.proto"; +import "amino/amino.proto"; + +option go_package = "github.com/pushchain/push-chain-node/x/ucallback/types"; + +// Msg defines the Msg service. +service Msg { + option (cosmos.msg.v1.service) = true; + + // VoteReadResult submits one universal validator's observation of a read + // request's outcome on the destination chain. + rpc VoteReadResult(MsgVoteReadResult) returns (MsgVoteReadResultResponse); + + // RetryReadExpiry reopens the expiry of a read the chain abandoned. + rpc RetryReadExpiry(MsgRetryReadExpiry) returns (MsgRetryReadExpiryResponse); + + // UpdateParams defines a governance operation for updating the parameters. + // + // Since: cosmos-sdk 0.47 + rpc UpdateParams(MsgUpdateParams) returns (MsgUpdateParamsResponse); +} + +// MsgUpdateParams is the Msg/UpdateParams request type. +// +// Since: cosmos-sdk 0.47 +message MsgUpdateParams { + option (cosmos.msg.v1.signer) = "authority"; + + // authority is the address of the governance account. + string authority = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; + + // params defines the parameters to update. + // + // NOTE: All parameters must be supplied. + Params params = 2 [(gogoproto.nullable) = false]; +} + +// MsgUpdateParamsResponse defines the response structure for executing a +// MsgUpdateParams message. +// +// Since: cosmos-sdk 0.47 +message MsgUpdateParamsResponse {} + +// MsgVoteReadResult is broadcast by a universal validator that has executed a +// read request against the destination chain. +// +// The ballot the vote lands on is derived from (request_id, result), so two +// validators reporting the same observation converge on one ballot and any +// disagreement produces a distinct ballot that never reaches quorum. Nothing +// validator-local may appear in `result` for that reason — notably there is no +// error message field. +message MsgVoteReadResult { + option (amino.name) = "ucallback/MsgVoteReadResult"; + option (cosmos.msg.v1.signer) = "signer"; + + // signer is the Cosmos address of the voting universal validator. + string signer = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; + + // request_id identifies the read request being voted on. + string request_id = 2; + + // result is the observation. Every field participates in the ballot key. + ReadResult result = 3; +} + +message MsgVoteReadResultResponse { + // finalized reports whether this vote carried the ballot to quorum. + bool finalized = 1; +} + +// MsgRetryReadExpiry is an admin escape hatch. For a read left ABORTED after +// MaxExpiryAttempts, this makes one more attempt at expireExternalRead. +// +// Needed because ABORTED is a dead end that nothing else can leave. The contract +// may still hold the request as pending with the funder's refund uncredited, and +// expireExternalRead is module-gated — no user, relayer or admin can call it +// directly. The sweeper will not retry either: ABORTED is terminal, so the record +// is out of PendingByExpiry. +// +// Each message is worth exactly one attempt: the attempt count is the record's own +// PCTx history, which is already at the limit, so a failure returns it to ABORTED +// with the new reason rather than granting a fresh budget. +message MsgRetryReadExpiry { + option (amino.name) = "ucallback/MsgRetryReadExpiry"; + option (cosmos.msg.v1.signer) = "signer"; + + // signer must equal uvalidator Params.Admin + string signer = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; + + // request_id of the abandoned read. + string request_id = 2; +} + +message MsgRetryReadExpiryResponse { + // settled reports whether the contract accepted the expiry this time. + bool settled = 1; +} diff --git a/proto/ucallback/v1/types.proto b/proto/ucallback/v1/types.proto new file mode 100644 index 00000000..fedd6715 --- /dev/null +++ b/proto/ucallback/v1/types.proto @@ -0,0 +1,182 @@ +syntax = "proto3"; +package ucallback.v1; + +import "gogoproto/gogo.proto"; +import "amino/amino.proto"; +import "uexecutor/v1/types.proto"; + +option go_package = "github.com/pushchain/push-chain-node/x/ucallback/types"; + +// ReadStatus is the outcome a universal validator observed for a read. +// ReadErrorCode is the deterministic reason a read produced an ERROR observation. +// Only non-transient failures appear here; transient failures never vote — the +// validator retries locally instead. +enum ReadErrorCode { + READ_ERROR_UNSPECIFIED = 0; // catch-all / other + READ_ERROR_INVALID_QUERY = 1; // envelope or params could not be decoded for this chain + READ_ERROR_UNSUPPORTED = 2; // chain does not support this query type or option + READ_ERROR_REVERTED = 3; // destination executed the request and returned a failure (EVM revert, HTTP 4xx) + READ_ERROR_NOT_FOUND = 4; // queried account, state, or field does not exist at the pinned point + READ_ERROR_INVALID_RESULT = 5; // destination returned data that could not be interpreted or encoded + READ_ERROR_REJECTED = 6; // request refused by validator policy before execution (web2 SSRF/blacklist) +} + +enum ReadStatus { + option (gogoproto.goproto_enum_stringer) = true; + + READ_STATUS_UNSPECIFIED = 0; + READ_STATUS_SUCCESS = 1; + READ_STATUS_ERROR = 2; +} + +// UniversalReadStatus is the lifecycle state of a read request on Push Chain. +enum UniversalReadStatus { + option (gogoproto.goproto_enum_stringer) = true; + + UNIVERSAL_READ_STATUS_UNSPECIFIED = 0; + UNIVERSAL_READ_STATUS_PENDING = 1; // ingested, awaiting votes + UNIVERSAL_READ_STATUS_VOTING = 2; // at least one vote, no quorum yet + UNIVERSAL_READ_STATUS_FULFILLED = 3; // callback dispatched successfully + UNIVERSAL_READ_STATUS_EXPIRED = 4; // expireExternalRead accepted by the contract + UNIVERSAL_READ_STATUS_FAILED = 5; // quorum reached but the callback reverted + + // Gave up: expireExternalRead failed MaxExpiryAttempts times and the contract + // never acknowledged the request. Distinct from EXPIRED because the contract may + // still hold it as pending — and since expireExternalRead is module-gated, no + // other caller can settle it. Requires manual intervention, the same sense as + // uexecutor's ABORTED. See error_msg on UniversalRead for the last failure. + UNIVERSAL_READ_STATUS_ABORTED = 6; +} + +// ReadRequest is one external read requested by an app on Push Chain. +// +// Every field is derived from the UniversalCallback.ReadRequested event, except +// created_at_height / requested_tx_hash / requested_log_index which come from the +// block the log was emitted in. +// +// NOTE: callbackGasLimit is deliberately absent. It is an argument to +// requestExternalReadSelf and is stored in the contract's _pending entry, but it is +// NOT emitted in ReadRequested. It has to be read back via getPendingRead(requestId) +// at fulfilment time, when the gas budget is actually needed. +message ReadRequest { + option (gogoproto.equal) = true; + + string request_id = 1; // uint256 requestId as 0x-prefixed hex + string destination_chain = 2; // CAIP-2, e.g. "eip155:1"; web2 uses "web2:https" + bytes owner = 3; // 20-byte address or 32-byte pubkey + bytes query = 4; // chain-specific envelope, abi.encode(...) + uint32 min_confirmations = 5; // uint16 on the contract; proto3 has no uint16 + uint64 destination_block_height = 6; // height on the destination chain; unused for web2 + uint64 expiry_block_height = 7; // Push Chain height at which the request expires + uint64 created_at_height = 8; // Push Chain height the request was observed at + + // Bookkeeping — recorded for operators, not consumed by universal validators. + string callback_target = 9; // the app contract the callback routes to + string original_funder = 10; // who paid the fee (the app, not the end user) + string fees_deposited = 11; // total msg.value paid, uint256 decimal string + string max_fee = 12; // uint256 as a decimal string + string requested_tx_hash = 13; // Push Chain tx that emitted ReadRequested + uint64 requested_log_index = 14; // log index within that tx + + // Fee split, taken from ReadRequested. protocol_fee is already in VaultPC by the + // time we see the log; only callback_budget is still escrowed on the contract. + string protocol_fee = 15; // uint256 decimal string + string callback_budget = 16; // uint256 decimal string — funds the callback + + // Gas ceiling the app declared for its own callback. The contract caps the inner + // call at this; we size the fulfil transaction from it. + uint64 callback_gas_limit = 17; + + // Where an unspent budget is refunded. From ReadSpec, not necessarily the funder. + string revert_recipient = 18; +} + +// ReadResult is the observation a universal validator votes on. +// +// Every field here is covered by the ballot key, so they must be byte-identical +// across validators for a ballot to converge. There is deliberately no error message +// field: local error text differs per node and would prevent agreement. +message ReadResult { + option (gogoproto.equal) = true; + + // 3 and 4 were observed_block_height and observed_block_hash. UniversalCallback + // does not take them and nothing else consumed them, so they are gone rather than + // carried as dead weight through the ballot key. + reserved 3, 4; + reserved "observed_block_height", "observed_block_hash"; + + ReadStatus status = 1; + bytes result_data = 2; // ABI-encoded payload delivered to the app + + // v2 ONLY — always empty in v1. See AggregateValue. + repeated AggregateValue aggregates = 5; + + // Why the read failed. Meaningful only when status is READ_STATUS_ERROR, and + // must be READ_ERROR_UNSPECIFIED otherwise — a SUCCESS vote carrying a code + // would hash to a different ballot than an honest SUCCESS vote and split quorum. + // + // An enum rather than free text on purpose: it participates in the ballot key, + // so it must be a value validators independently converge on. A string invites + // fmt.Sprintf("%v", err), whose text varies by RPC provider even for identical + // on-chain failures. + ReadErrorCode error_code = 6; +} + +// AggregateValue is one field the module combines across validators instead of +// requiring byte-equality on — a price, say, where honest nodes legitimately differ. +// +// NOT USED IN v1. The universal client rejects any extract mode other than IDENTICAL +// (externalchains/web2/read_envelope.go), so this list is always empty today. The field +// is reserved now because adding it later would change how ballots are keyed on a live +// chain, which is consensus-breaking. In v1 the ballot key covers all of fields 1-4; in +// v2 it must cover only fields 1-4 with `aggregates` EXCLUDED, so computing the key over +// "the identical subset" from the start keeps v2 purely additive. +// +// v2 ALSO REQUIRES REPLACING THE BALLOT MECHANISM, not just populating this field. +// Ballots today store a binary VoteResult{SUCCESS|FAILURE} against an ID that encodes the +// observation, so distinct observations produce distinct ballots and none reaches quorum +// when validators report different numbers. Ballots therefore cannot retain per-validator +// values, which is exactly what a median needs. v2 has to keep each validator's +// AggregateValue set in module state and reduce at quorum — the pattern x/uexecutor +// already uses for gas-price medians in keeper/chain_meta.go, which bypasses ballots for +// the same reason. +message AggregateValue { + option (gogoproto.equal) = true; + + uint32 extract_index = 1; // index into the query envelope's extract list + uint32 mode = 2; // aggregation mode; only MEDIAN is planned + bytes value = 3; // big-endian uint256/int256 +} + +// UniversalRead is the full lifecycle record of one read request. +// +// The read-side sibling of uexecutor's UniversalTx, but deliberately not the same +// shape: a read is triggered by a Push Chain event rather than an external inbound, +// performs no external write, and settles in exactly one Push Chain transaction. +message UniversalRead { + option (amino.name) = "ucallback/universal_read"; + option (gogoproto.equal) = true; + + string id = 1; // requestId, same value as request.request_id + ReadRequest request = 2; + ReadResult result = 3; // set once the ballot finalises + UniversalReadStatus status = 4; + string ballot_key = 5; + + // Push Chain execution attempts — fulfilExternalCallback and expireExternalRead. + // Repeated because fulfilment can be retried and may be followed by an expiry. + repeated uexecutor.v1.PCTx pc_tx = 6; + + // Why the chain stopped acting on this read. Populated on the ABORTED and FAILED + // paths from the EVM result, so it is identical on every node — this is our own + // execution outcome, not a validator's observation, and it never touches a ballot. + string error_msg = 7; + + // How many times the sweeper has called expireExternalRead for this read. + // + // An explicit counter rather than len(pc_tx): pc_tx accumulates every EVM attempt + // on the request, including a failed fulfilment that left it in flight, so + // counting entries would silently shorten the retry budget for exactly the reads + // that already had trouble. + uint32 expiry_attempts = 8; +} diff --git a/proto/uvalidator/v1/ballot.proto b/proto/uvalidator/v1/ballot.proto index d1353e9e..63ed6971 100644 --- a/proto/uvalidator/v1/ballot.proto +++ b/proto/uvalidator/v1/ballot.proto @@ -30,6 +30,7 @@ enum BallotObservationType { BALLOT_OBSERVATION_TYPE_OUTBOUND_TX = 2; BALLOT_OBSERVATION_TYPE_TSS_KEY = 3; BALLOT_OBSERVATION_TYPE_FUND_MIGRATION = 4; + BALLOT_OBSERVATION_TYPE_READ_RESULT = 5; } // --------------------------- diff --git a/scripts/protocgen.sh b/scripts/protocgen.sh index 551766d3..f7c0e512 100755 --- a/scripts/protocgen.sh +++ b/scripts/protocgen.sh @@ -28,7 +28,11 @@ rm -rf github.com # Copy files over for dep injection rm -rf api && mkdir api -custom_modules=$(find . -name 'module' -type d -not -path "./proto/*" -not -path "./.cache/*") +# NOTE: exclude ./compat/* — compat/orm-api/module is a vendored compatibility shim, not a +# generated proto module. Without this it is matched here, moved into ./api/ and then deleted by +# the `rm -rf $module` below, which breaks the `cosmossdk.io/api/cosmos/orm => ./compat/orm-api` +# replace in go.mod and fails the `go mod tidy` at the end of `make proto-gen`. +custom_modules=$(find . -name 'module' -type d -not -path "./proto/*" -not -path "./.cache/*" -not -path "./compat/*") # get the 1 up directory (so ./cosmos/mint/module becomes ./cosmos/mint) # remove the relative path starter from base namespaces. so ./cosmos/mint becomes cosmos/mint diff --git a/test/integration/ucallback/burn_test.go b/test/integration/ucallback/burn_test.go new file mode 100644 index 00000000..0a4641c6 --- /dev/null +++ b/test/integration/ucallback/burn_test.go @@ -0,0 +1,109 @@ +package integrationtest + +import ( + "math/big" + "testing" + + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + evmtypes "github.com/cosmos/evm/x/vm/types" + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" + + utils "github.com/pushchain/push-chain-node/test/utils" + pchaintypes "github.com/pushchain/push-chain-node/types" + uregistrytypes "github.com/pushchain/push-chain-node/x/uregistry/types" +) + +func callbackContractAddr() sdk.AccAddress { + return sdk.AccAddress(common.HexToAddress( + uregistrytypes.SYSTEM_CONTRACTS["UNIVERSAL_CALLBACK"].Address).Bytes()) +} + +// TakeAndBurn must genuinely reduce total supply, not move coins somewhere. +// +// This is the claim a fake bank cannot make: it needs the real Burner permission, +// the real blocked-address exemption, and the real supply accounting all agreeing. +func TestTakeAndBurn_ReducesTotalSupply(t *testing.T) { + chainApp, ctx, _ := utils.SetAppWithValidators(t) + k := chainApp.UcallbackKeeper + bank := chainApp.BankKeeper + + // escrow sitting on UniversalCallback, as it would be after a request + escrow := sdkmath.NewInt(5_000_000_000_000_000) + coins := sdk.NewCoins(sdk.NewCoin(pchaintypes.BaseDenom, escrow)) + require.NoError(t, bank.MintCoins(ctx, evmtypes.ModuleName, coins)) + require.NoError(t, bank.SendCoinsFromModuleToAccount( + ctx, evmtypes.ModuleName, callbackContractAddr(), coins)) + + supplyBefore := bank.GetSupply(ctx, pchaintypes.BaseDenom).Amount + contractBefore := bank.GetBalance(ctx, callbackContractAddr(), pchaintypes.BaseDenom).Amount + require.Equal(t, escrow, contractBefore) + + burn := big.NewInt(2_000_000_000_000_000) + require.NoError(t, k.TakeAndBurn(ctx, burn)) + + supplyAfter := bank.GetSupply(ctx, pchaintypes.BaseDenom).Amount + contractAfter := bank.GetBalance(ctx, callbackContractAddr(), pchaintypes.BaseDenom).Amount + + require.Equal(t, sdkmath.NewIntFromBigInt(burn), supplyBefore.Sub(supplyAfter), + "supply must fall by exactly the burned amount") + require.Equal(t, sdkmath.NewIntFromBigInt(burn), contractBefore.Sub(contractAfter), + "and it must come out of the contract, not anywhere else") + + // nothing may be left parked in the module — it takes and burns in one step + modAddr, _ := k.GetModuleAddress(ctx) + modBal := bank.GetBalance(ctx, sdk.AccAddress(modAddr.Bytes()), pchaintypes.BaseDenom) + require.True(t, modBal.Amount.IsZero(), "the module must not retain what it burned") +} + +// A burn larger than the contract holds must fail cleanly and destroy nothing — +// the affordability gate should prevent it, so this is the backstop. +func TestTakeAndBurn_FailsWithoutSufficientEscrow(t *testing.T) { + chainApp, ctx, _ := utils.SetAppWithValidators(t) + k := chainApp.UcallbackKeeper + bank := chainApp.BankKeeper + + supplyBefore := bank.GetSupply(ctx, pchaintypes.BaseDenom).Amount + + err := k.TakeAndBurn(ctx, big.NewInt(1_000_000)) + require.Error(t, err, "cannot take escrow the contract does not hold") + + require.Equal(t, supplyBefore, bank.GetSupply(ctx, pchaintypes.BaseDenom).Amount, + "a failed take must burn nothing") +} + +// Zero and nil are no-ops, not errors — a callback that consumed nothing settles +// without a burn. +func TestTakeAndBurn_ZeroIsANoop(t *testing.T) { + chainApp, ctx, _ := utils.SetAppWithValidators(t) + k := chainApp.UcallbackKeeper + + before := chainApp.BankKeeper.GetSupply(ctx, pchaintypes.BaseDenom).Amount + require.NoError(t, k.TakeAndBurn(ctx, big.NewInt(0))) + require.NoError(t, k.TakeAndBurn(ctx, nil)) + require.Equal(t, before, chainApp.BankKeeper.GetSupply(ctx, pchaintypes.BaseDenom).Amount) +} + +// CallbackCost must price against the chain's real base fee, not a fixture. +func TestCallbackCost_UsesTheChainBaseFee(t *testing.T) { + chainApp, ctx, _ := utils.SetAppWithValidators(t) + k := chainApp.UcallbackKeeper + + // The bare harness leaves feemarket params unset; pin a base fee the way the + // uexecutor integration tests do, then read it back through the same keeper + // x/ucallback uses in production. + params := chainApp.FeeMarketKeeper.GetParams(ctx) + params.BaseFee = sdkmath.LegacyNewDec(1_000_000_000) + require.NoError(t, chainApp.FeeMarketKeeper.SetParams(ctx, params)) + + baseFee := chainApp.FeeMarketKeeper.GetBaseFee(ctx) + require.False(t, baseFee.IsNil(), "the chain must expose a base fee") + require.Equal(t, sdkmath.LegacyNewDec(1_000_000_000), baseFee) + + cost, err := k.CallbackCost(ctx, 100_000) + require.NoError(t, err) + + want := new(big.Int).Mul(big.NewInt(100_000), baseFee.TruncateInt().BigInt()) + require.Equal(t, want, cost) +} diff --git a/test/integration/ucallback/contract_call_test.go b/test/integration/ucallback/contract_call_test.go new file mode 100644 index 00000000..bc63a6b6 --- /dev/null +++ b/test/integration/ucallback/contract_call_test.go @@ -0,0 +1,134 @@ +package integrationtest + +import ( + "math/big" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + evmtypes "github.com/cosmos/evm/x/vm/types" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" + + "github.com/pushchain/push-chain-node/app" + utils "github.com/pushchain/push-chain-node/test/utils" + ucallbacktypes "github.com/pushchain/push-chain-node/x/ucallback/types" +) + +// The deployed contract must be the one we think it is: same reserved address, and +// the access-control immutable baked to the x/ucallback module account. +// +// A unit test asserts our ABI encoding; only this asserts the bytecode agrees. +func TestUniversalCallback_DeploysWithOurModuleAddress(t *testing.T) { + chainApp, ctx, _ := utils.SetAppWithValidators(t) + + addr := utils.SetupUniversalCallback(t, chainApp, ctx) + code := chainApp.EVMKeeper.GetCode(ctx, common.BytesToHash( + chainApp.EVMKeeper.GetAccountOrEmpty(ctx, addr).CodeHash)) + require.NotEmpty(t, code, "the contract must have code at its reserved address") + + modAddr, _ := chainApp.UcallbackKeeper.GetModuleAddress(ctx) + require.Contains(t, common.Bytes2Hex(code), common.Bytes2Hex(modAddr.Bytes()), + "the module address must be baked into the deployed code, or every call reverts") +} + +// The real contract's access control must admit our module and nothing else. The +// contract used to hardcode x/uexecutor's address; only a real call can show that +// the pairing is now with us. +func TestUniversalCallback_RejectsNonModuleCallers(t *testing.T) { + chainApp, ctx, _ := utils.SetAppWithValidators(t) + addr := utils.SetupUniversalCallback(t, chainApp, ctx) + + callbackABI, err := ucallbacktypes.ParseUniversalCallbackABI() + require.NoError(t, err) + + stranger := provisionEOA(t, chainApp, ctx, "0x000000000000000000000000000000000000dEaD") + res, callErr := call(t, chainApp, ctx, callbackABI, stranger, addr, + false /* isModuleSender */, nil /* manualNonce: module senders only */) + + // A revert yields BOTH a response and an error — see ClassifyCall's ordering. + require.Error(t, callErr, "onlyUCallbackModule must reject a stranger") + require.NotNil(t, res, "a revert still returns the response carrying the reason") + require.NotEmpty(t, res.VmError) + + require.Equal(t, ucallbacktypes.CallUnsettled, + ucallbacktypes.ClassifyCall(res.VmError, res.Ret, callErr), + "a rejected caller settled nothing, so the read must stay expirable") +} + +// Our module reaches past access control. The call still reverts — the request does +// not exist — but on a different error, which is the point: the caller is admitted +// and the contract is evaluating the request itself. +func TestUniversalCallback_AdmitsTheModule(t *testing.T) { + chainApp, ctx, _ := utils.SetAppWithValidators(t) + addr := utils.SetupUniversalCallback(t, chainApp, ctx) + + callbackABI, err := ucallbacktypes.ParseUniversalCallbackABI() + require.NoError(t, err) + modAddr, _ := chainApp.UcallbackKeeper.GetModuleAddress(ctx) + + res, callErr := call(t, chainApp, ctx, callbackABI, modAddr, addr, true, nonceArg()) + require.Error(t, callErr, "an unknown request still reverts") + require.NotNil(t, res) + + stranger := provisionEOA(t, chainApp, ctx, "0x000000000000000000000000000000000000dEaD") + strangerRes, _ := call(t, chainApp, ctx, callbackABI, stranger, addr, false, nil) + require.NotNil(t, strangerRes) + + require.NotEqual(t, common.Bytes2Hex(strangerRes.Ret), common.Bytes2Hex(res.Ret), + "the module must fail for a different reason than a rejected caller") + + // and specifically: not the access-control error + require.Equal(t, ucallbacktypes.CallerIsNotUCallbackModuleSelector(), + selectorOf(strangerRes.Ret), "stranger is refused by access control") + require.NotEqual(t, ucallbacktypes.CallerIsNotUCallbackModuleSelector(), + selectorOf(res.Ret), "the module must get past access control") +} + +// call issues expireExternalRead the way production does — via +// DerivedEVMCallWithData, which preserves the response on a revert. The ABI-typed +// DerivedEVMCall wrapper returns (nil, err) instead, discarding res.Ret; a test +// routed through it could not see which error the contract raised. +func call( + t *testing.T, chainApp *app.ChainApp, ctx sdk.Context, callbackABI abi.ABI, + from, contract common.Address, isModuleSender bool, nonce *uint64, +) (*evmtypes.MsgEthereumTxResponse, error) { + t.Helper() + data, err := callbackABI.Pack(ucallbacktypes.MethodExpireExternalRead, requestIDArg()) + require.NoError(t, err) + return chainApp.EVMKeeper.DerivedEVMCallWithData( + ctx, from, &contract, data, + true /* commit */, false /* gasless */, isModuleSender, + big.NewInt(0), gasLimitArg(), nonce, + ) +} + +func selectorOf(ret []byte) [4]byte { + var s [4]byte + if len(ret) >= 4 { + copy(s[:], ret[:4]) + } + return s +} + +// requestIDArg is an arbitrary uint256 request id for calls expected to revert +// before the id matters. +func requestIDArg() *big.Int { return big.NewInt(0xaa) } + +func nonceArg() *uint64 { n := uint64(0); return &n } + +// gasLimitArg is comfortably above intrinsic cost. Passing nil makes DerivedEVMCall +// estimate, and an estimate below intrinsic gas is rejected before the EVM runs — +// which would tell us nothing about the contract. +func gasLimitArg() *big.Int { return big.NewInt(500_000) } + +// provisionEOA creates an account for a bare address. A non-module sender has its +// nonce read from the account keeper, which errors when the account does not exist — +// the call would fail before the EVM, telling us nothing about access control. +func provisionEOA(t *testing.T, chainApp *app.ChainApp, ctx sdk.Context, hex string) common.Address { + t.Helper() + addr := common.HexToAddress(hex) + acc := chainApp.AccountKeeper.NewAccountWithAddress(ctx, sdk.AccAddress(addr.Bytes())) + chainApp.AccountKeeper.SetAccount(ctx, acc) + return addr +} diff --git a/test/integration/ucallback/ingest_real_event_test.go b/test/integration/ucallback/ingest_real_event_test.go new file mode 100644 index 00000000..1c4b2e34 --- /dev/null +++ b/test/integration/ucallback/ingest_real_event_test.go @@ -0,0 +1,179 @@ +package integrationtest + +import ( + "math/big" + "os" + "strings" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + evmtypes "github.com/cosmos/evm/x/vm/types" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" + + utils "github.com/pushchain/push-chain-node/test/utils" + ucallbacktypes "github.com/pushchain/push-chain-node/x/ucallback/types" +) + +// The full inbound half: the contract creates a request, emits ReadRequested, and +// we ingest that log into a UniversalRead. +// +// This is the one test where the event we decode was produced by the contract +// rather than by our own encoder. Every other event test round-trips through the +// same ABI fragment on both sides, so a wrong fragment agrees with itself — which +// is exactly how callbackGasLimit sat in the wrong position undetected. +func TestIngest_DecodesAContractEmittedEvent(t *testing.T) { + chainApp, ctx, _ := utils.SetAppWithValidators(t) + k := chainApp.UcallbackKeeper + + contract := utils.SetupUniversalCallback(t, chainApp, ctx) + core := utils.SetupMockUniversalCoreForReads(t, chainApp, ctx) + + // _universalCore is storage slot 0; the fixture writes runtime code directly, + // so initialize() never ran to set it. + chainApp.EVMKeeper.SetState(ctx, contract, + common.BigToHash(big.NewInt(0)), common.BytesToHash(core.Bytes()).Bytes()) + + requester := provisionEOA(t, chainApp, ctx, "0x00000000000000000000000000000000000A11CE") + deposit := big.NewInt(4_000_000_000_000_000) + fund(t, chainApp, ctx, sdk.AccAddress(requester.Bytes()), new(big.Int).Mul(deposit, big.NewInt(10))) + + const ( + wantGasLimit = uint64(250_000) + wantMinConf = uint16(6) + wantBlockNum = uint64(8_000_000) + ) + wantExpiry := uint64(ctx.BlockHeight()) + 500 + revertRecipient := common.HexToAddress("0x00000000000000000000000000000000000BEEF1") + + reqABI := loadRequestABI(t) + data, err := reqABI.Pack("requestExternalReadSelf", + readSpecArg{ + Account: accountArg{ + ChainNamespace: "eip155", + ChainId: "11155111", + Owner: common.FromHex("0x1111111111111111111111111111111111111111"), + }, + Query: common.FromHex("0xdeadbeef"), + MinConfirmations: wantMinConf, + BlockNumber: wantBlockNum, + ExpiryPushChainHeight: wantExpiry, + MaxFee: new(big.Int).Mul(deposit, big.NewInt(2)), + RevertRecipient: revertRecipient, + }, + [4]byte{0x11, 0x22, 0x33, 0x44}, + wantGasLimit, + ) + require.NoError(t, err) + + res, err := chainApp.EVMKeeper.DerivedEVMCallWithData( + ctx, requester, &contract, data, + true /* commit */, false, false, + deposit, big.NewInt(2_000_000), nil, + ) + require.NoError(t, err, "creating a read request must succeed: %v", res) + require.NotEmpty(t, res.Logs, "the contract must have emitted ReadRequested") + + // --- the part under test ----------------------------------------------------- + require.NoError(t, k.IngestReadRequests(ctx, res)) + + var recorded []ucallbacktypes.UniversalRead + require.NoError(t, k.IterateReadsByTxHash(ctx, res.Hash, + func(ur ucallbacktypes.UniversalRead) bool { + recorded = append(recorded, ur) + return false + })) + require.Len(t, recorded, 1, + "exactly one read must be ingested from a contract-emitted ReadRequested") + + ur := recorded[0] + req := ur.Request + require.Equal(t, ucallbacktypes.UniversalReadStatus_UNIVERSAL_READ_STATUS_PENDING, ur.Status) + + // Field-by-field against what we asked the contract for. A signature that + // decodes but misaligns would show up right here as scrambled values. + require.Equal(t, wantGasLimit, req.CallbackGasLimit, "callbackGasLimit") + require.Equal(t, uint32(wantMinConf), req.MinConfirmations, "minConfirmations") + require.Equal(t, wantBlockNum, req.DestinationBlockHeight, "blockNumber") + require.Equal(t, wantExpiry, req.ExpiryBlockHeight, "expiryPushChainHeight") + require.Equal(t, "eip155:11155111", req.DestinationChain, "chain") + require.Equal(t, requester.Hex(), req.CallbackTarget, "callbackTarget") + require.Equal(t, requester.Hex(), req.OriginalFunder, "originalFunder") + require.Equal(t, revertRecipient.Hex(), req.RevertRecipient, "revertRecipient") + require.Equal(t, deposit.String(), req.FeesDeposited, "totalPaid") + + // the mock prices reads at zero, so the whole deposit is callback budget + require.Equal(t, "0", req.ProtocolFee, "protocolFee") + require.Equal(t, deposit.String(), req.CallbackBudget, "callbackBudget") + + // and the contract must agree this request is live and escrowed + views := loadViewABI(t) + id, ok := new(big.Int).SetString(strings.TrimPrefix(req.RequestId, "0x"), 16) + require.True(t, ok) + require.Equal(t, uint8(1), // PENDING + staticCall(t, chainApp, ctx, views, contract, "statusOf", id)[0].(uint8)) + require.Zero(t, deposit.Cmp( + staticCall(t, chainApp, ctx, views, contract, "totalEscrowed")[0].(*big.Int)), + "the deposit must be escrowed on the contract") + + // ingest is idempotent -- the same receipt replayed must not duplicate + require.NoError(t, k.IngestReadRequests(ctx, res)) + var again int + require.NoError(t, k.IterateReadsByTxHash(ctx, res.Hash, + func(ucallbacktypes.UniversalRead) bool { again++; return false })) + require.Equal(t, 1, again, "replaying a receipt must not create a second record") +} + +// A ReadRequested-shaped log from an address that is NOT UniversalCallback must be +// ignored. Without the address check anyone could mint read requests by emitting a +// matching log from their own contract. +func TestIngest_IgnoresLogsFromOtherContracts(t *testing.T) { + chainApp, ctx, _ := utils.SetAppWithValidators(t) + k := chainApp.UcallbackKeeper + + forged := &evmtypes.MsgEthereumTxResponse{ + Hash: "0xforged", + Logs: []*evmtypes.Log{{ + Address: "0x000000000000000000000000000000000000dEaD", + Topics: []string{ + ucallbacktypes.ReadRequestedEventSig.Hex(), + common.BigToHash(big.NewInt(1)).Hex(), + common.BytesToHash(common.FromHex("0x02")).Hex(), + common.BytesToHash(common.FromHex("0x03")).Hex(), + }, + Data: []byte{}, + }}, + } + require.NoError(t, k.IngestReadRequests(ctx, forged)) + + var n int + require.NoError(t, k.IterateReadsByTxHash(ctx, "0xforged", + func(ucallbacktypes.UniversalRead) bool { n++; return false })) + require.Zero(t, n, "a look-alike log from another address must be ignored") +} + +type accountArg struct { + ChainNamespace string + ChainId string + Owner []byte +} + +type readSpecArg struct { + Account accountArg + Query []byte + MinConfirmations uint16 + BlockNumber uint64 + ExpiryPushChainHeight uint64 + MaxFee *big.Int + RevertRecipient common.Address +} + +func loadRequestABI(t *testing.T) abi.ABI { + t.Helper() + raw, err := os.ReadFile("testdata/request_external_read_self.json") + require.NoError(t, err) + parsed, err := abi.JSON(strings.NewReader(string(raw))) + require.NoError(t, err) + return parsed +} diff --git a/test/integration/ucallback/keeper_path_test.go b/test/integration/ucallback/keeper_path_test.go new file mode 100644 index 00000000..e35f0173 --- /dev/null +++ b/test/integration/ucallback/keeper_path_test.go @@ -0,0 +1,223 @@ +package integrationtest + +import ( + "context" + "math/big" + "testing" + + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" + + "github.com/pushchain/push-chain-node/app" + utils "github.com/pushchain/push-chain-node/test/utils" + pchaintypes "github.com/pushchain/push-chain-node/types" + ucallbackkeeper "github.com/pushchain/push-chain-node/x/ucallback/keeper" + ucallbacktypes "github.com/pushchain/push-chain-node/x/ucallback/types" +) + +// readFixture is one request that exists in BOTH places it has to exist: seeded +// into the contract's storage, and recorded in the keeper. Production gets there by +// ingesting an event; these tests get there directly so the settle and expiry paths +// can be exercised without standing up UniversalCore and a fee schedule. +type readFixture struct { + id *big.Int + idHex string + budget *big.Int + gasLimit uint64 + expiry uint64 + recipient common.Address + contract common.Address +} + +func newReadFixture( + t *testing.T, chainApp *app.ChainApp, ctx sdk.Context, + id int64, budget *big.Int, gasLimit uint64, expiry uint64, +) readFixture { + t.Helper() + contract := utils.SetupUniversalCallback(t, chainApp, ctx) + + requestID := big.NewInt(id) + target := provisionEOA(t, chainApp, ctx, "0x00000000000000000000000000000000000c0FFE") + recipient := provisionEOA(t, chainApp, ctx, "0x00000000000000000000000000000000000Fee00") + + seedPendingRead(t, chainApp, ctx, contract, requestID, pendingRead{ + callbackTarget: target, + callbackSelector: [4]byte{0xaa, 0xbb, 0xcc, 0xdd}, + callbackGasLimit: gasLimit, + originalFunder: target, + expiryHeight: expiry, + revertRecipient: recipient, + callbackBudget: budget, + }) + fund(t, chainApp, ctx, sdk.AccAddress(contract.Bytes()), budget) + + f := readFixture{ + id: requestID, idHex: hexID(requestID), budget: budget, + gasLimit: gasLimit, expiry: expiry, recipient: recipient, contract: contract, + } + require.NoError(t, chainApp.UcallbackKeeper.SetUniversalRead(ctx, f.universalRead( + ucallbacktypes.UniversalReadStatus_UNIVERSAL_READ_STATUS_PENDING, nil))) + return f +} + +func (f readFixture) universalRead( + status ucallbacktypes.UniversalReadStatus, result *ucallbacktypes.ReadResult, +) ucallbacktypes.UniversalRead { + return ucallbacktypes.UniversalRead{ + Id: f.idHex, + Status: status, + Result: result, + Request: &ucallbacktypes.ReadRequest{ + RequestId: f.idHex, + DestinationChain: "eip155:11155111", + ExpiryBlockHeight: f.expiry, + CallbackBudget: f.budget.String(), + CallbackGasLimit: f.gasLimit, + RevertRecipient: f.recipient.Hex(), + RequestedTxHash: "0xabc", + }, + } +} + +func okResult() *ucallbacktypes.ReadResult { + return &ucallbacktypes.ReadResult{ + Status: ucallbacktypes.ReadStatus_READ_STATUS_SUCCESS, + ResultData: []byte{0x01, 0x02}, + } +} + +// FulfilRead is the whole settle path: affordability gate, the contract call, +// outcome classification, status transition, gas report and burn. The e2e test +// calls CallFulfillExternalCallback directly, so none of the logic wrapping it had +// ever run against a real EVM. +func TestFulfilRead_SettlesAndBurns(t *testing.T) { + chainApp, ctx, _ := utils.SetAppWithValidators(t) + k := chainApp.UcallbackKeeper + bank := chainApp.BankKeeper + + f := newReadFixture(t, chainApp, ctx, 0x11, big.NewInt(3_000_000_000_000_000), 200_000, + uint64(ctx.BlockHeight())+1000) + + supplyBefore := bank.GetSupply(ctx, pchaintypes.BaseDenom).Amount + require.NoError(t, k.FulfilRead(ctx, f.universalRead( + ucallbacktypes.UniversalReadStatus_UNIVERSAL_READ_STATUS_VOTING, okResult()))) + + got, ok := k.GetUniversalRead(ctx, f.idHex) + require.True(t, ok) + require.Equal(t, ucallbacktypes.UniversalReadStatus_UNIVERSAL_READ_STATUS_FULFILLED, got.Status, + "a successful callback must leave the read FULFILLED; err=%q", got.ErrorMsg) + require.Empty(t, got.ErrorMsg, "a clean fulfilment records no error") + + // the contract agrees it is finished + require.Equal(t, uint8(3), // SETTLED + staticCall(t, chainApp, ctx, loadViewABI(t), f.contract, "statusOf", f.id)[0].(uint8)) + + // and value was actually destroyed + supplyAfter := bank.GetSupply(ctx, pchaintypes.BaseDenom).Amount + require.True(t, supplyAfter.LT(supplyBefore), "fulfilment must burn the consumed budget") + + // both EVM calls are recorded for offchain tracing + require.Len(t, got.PcTx, 2, "fulfil and report must each leave a PcTx") + + // settled reads leave the in-flight index, so the sweeper will not touch it + require.NoError(t, chainApp.UcallbackKeeper.SweepExpired( + ctx.WithBlockHeight(int64(f.expiry)+1))) + still, _ := k.GetUniversalRead(ctx, f.idHex) + require.Equal(t, ucallbacktypes.UniversalReadStatus_UNIVERSAL_READ_STATUS_FULFILLED, still.Status, + "a settled read must not be re-expired by the sweeper") +} + +// A request whose budget cannot cover its declared gas limit must not be executed: +// it stays in flight so the sweeper refunds the funder in full. +func TestFulfilRead_UnaffordableStaysInFlight(t *testing.T) { + chainApp, ctx, _ := utils.SetAppWithValidators(t) + k := chainApp.UcallbackKeeper + + // 1 wei of budget against a 1M gas limit + f := newReadFixture(t, chainApp, ctx, 0x12, big.NewInt(1), 1_000_000, + uint64(ctx.BlockHeight())+1000) + + require.NoError(t, k.FulfilRead(ctx, f.universalRead( + ucallbacktypes.UniversalReadStatus_UNIVERSAL_READ_STATUS_VOTING, okResult()))) + + got, ok := k.GetUniversalRead(ctx, f.idHex) + require.True(t, ok) + require.Equal(t, ucallbacktypes.UniversalReadStatus_UNIVERSAL_READ_STATUS_VOTING, got.Status, + "an unaffordable read must keep its status so expiry still owns it") + require.Equal(t, ucallbackkeeper.ErrBudgetTooSmall, got.ErrorMsg) + require.Empty(t, got.PcTx, "nothing may be sent to the contract") + + // the contract must still see it as PENDING, i.e. refundable + require.Equal(t, uint8(1), + staticCall(t, chainApp, ctx, loadViewABI(t), f.contract, "statusOf", f.id)[0].(uint8)) +} + +// The sweep is the path that runs unattended every block, so a failure here is a +// chain-wide event rather than one bad request. It must expire the request on the +// contract, refund the funder, and retire our record. +func TestSweepExpired_RefundsThroughTheRealContract(t *testing.T) { + chainApp, ctx, _ := utils.SetAppWithValidators(t) + k := chainApp.UcallbackKeeper + bank := chainApp.BankKeeper + + expiry := uint64(ctx.BlockHeight()) + 5 + budget := big.NewInt(2_000_000_000_000_000) + f := newReadFixture(t, chainApp, ctx, 0x21, budget, 200_000, expiry) + + recipientBefore := bank.GetBalance(ctx, + sdk.AccAddress(f.recipient.Bytes()), pchaintypes.BaseDenom).Amount + supplyBefore := bank.GetSupply(ctx, pchaintypes.BaseDenom).Amount + + // before the deadline the sweep must leave it strictly alone + require.NoError(t, k.SweepExpired(ctx.WithBlockHeight(int64(expiry)-1))) + early, _ := k.GetUniversalRead(ctx, f.idHex) + require.Equal(t, ucallbacktypes.UniversalReadStatus_UNIVERSAL_READ_STATUS_PENDING, early.Status, + "a live request must survive the sweep") + + // at the deadline it must be retired + swept := ctx.WithBlockHeight(int64(expiry)) + require.NoError(t, k.SweepExpired(swept)) + + got, ok := k.GetUniversalRead(ctx, f.idHex) + require.True(t, ok) + require.Equal(t, ucallbacktypes.UniversalReadStatus_UNIVERSAL_READ_STATUS_EXPIRED, got.Status, + "err=%q", got.ErrorMsg) + + require.Equal(t, uint8(4), // EXPIRED + staticCall(t, chainApp, swept, loadViewABI(t), f.contract, "statusOf", f.id)[0].(uint8), + "the contract must agree the request is expired") + + // expiry refunds the WHOLE budget — nothing is burned on this path + recipientAfter := bank.GetBalance(swept, + sdk.AccAddress(f.recipient.Bytes()), pchaintypes.BaseDenom).Amount + require.Equal(t, sdkmath.NewIntFromBigInt(budget), recipientAfter.Sub(recipientBefore), + "an expired request must refund the funder in full") + require.Equal(t, supplyBefore, bank.GetSupply(swept, pchaintypes.BaseDenom).Amount, + "expiry must not burn anything") + + // idempotent: running again must not double-refund + require.NoError(t, k.SweepExpired(swept.WithBlockHeight(int64(expiry)+1))) + require.Equal(t, recipientAfter, bank.GetBalance(swept, + sdk.AccAddress(f.recipient.Bytes()), pchaintypes.BaseDenom).Amount, + "a second sweep must be a no-op") +} + +// EndBlock is what actually drives the sweep on a live chain. Exercising +// SweepExpired directly would not prove the module is wired into the block cycle. +func TestEndBlock_DrivesTheSweep(t *testing.T) { + chainApp, ctx, _ := utils.SetAppWithValidators(t) + k := chainApp.UcallbackKeeper + + expiry := uint64(ctx.BlockHeight()) + 3 + f := newReadFixture(t, chainApp, ctx, 0x22, big.NewInt(1_500_000_000_000_000), 200_000, expiry) + + require.NoError(t, chainApp.ModuleManager.Modules[ucallbacktypes.ModuleName].(interface { + EndBlock(context.Context) error + }).EndBlock(ctx.WithBlockHeight(int64(expiry)))) + + got, _ := k.GetUniversalRead(ctx, f.idHex) + require.Equal(t, ucallbacktypes.UniversalReadStatus_UNIVERSAL_READ_STATUS_EXPIRED, got.Status, + "EndBlock must retire an overdue read") +} diff --git a/test/integration/ucallback/lifecycle_e2e_test.go b/test/integration/ucallback/lifecycle_e2e_test.go new file mode 100644 index 00000000..f6107b54 --- /dev/null +++ b/test/integration/ucallback/lifecycle_e2e_test.go @@ -0,0 +1,283 @@ +package integrationtest + +import ( + "math/big" + "os" + "strings" + "testing" + + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + evmtypes "github.com/cosmos/evm/x/vm/types" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + "github.com/stretchr/testify/require" + + "github.com/pushchain/push-chain-node/app" + utils "github.com/pushchain/push-chain-node/test/utils" + pchaintypes "github.com/pushchain/push-chain-node/types" + ucallbacktypes "github.com/pushchain/push-chain-node/x/ucallback/types" +) + +// Storage slots of UniversalCallback, from +// `forge inspect UniversalCallback storageLayout`. +// +// Seeding storage is how a test reaches a PENDING request without standing up +// UniversalCore, a fee schedule and a callback-target contract just to call +// requestExternalReadSelf. seedPendingRead reads the result back through the +// contract's own getters, so if any of this drifts the test fails loudly rather +// than quietly exercising the wrong state. +const ( + slotStatus = 2 // mapping(uint256 => RequestStatus) + slotPending = 3 // mapping(uint256 => PendingRead) + slotTotalEscrowed = 6 // uint256 +) + +// PendingRead packs into 4 slots: +// +// +0 callbackTarget (20) | callbackSelector (4) | callbackGasLimit (8) +// +1 originalFunder (20) | expiryHeight (8) +// +2 revertRecipient (20) +// +3 callbackBudget (32) +type pendingRead struct { + callbackTarget common.Address + callbackSelector [4]byte + callbackGasLimit uint64 + originalFunder common.Address + expiryHeight uint64 + revertRecipient common.Address + callbackBudget *big.Int +} + +// mappingSlot is keccak256(pad32(key) ++ pad32(slot)), Solidity's layout for +// mapping(uint256 => _). +func mappingSlot(key *big.Int, slot int64) common.Hash { + var buf []byte + buf = append(buf, common.BigToHash(key).Bytes()...) + buf = append(buf, common.BigToHash(big.NewInt(slot)).Bytes()...) + return crypto.Keccak256Hash(buf) +} + +func slotPlus(base common.Hash, n int64) common.Hash { + return common.BigToHash(new(big.Int).Add(base.Big(), big.NewInt(n))) +} + +// packed builds a 32-byte word from little-end-first fields, matching how Solidity +// packs a struct slot: the first-declared field occupies the low-order bytes. +func packed(parts ...[]byte) common.Hash { + var w [32]byte + off := 0 + for _, p := range parts { + copy(w[32-off-len(p):32-off], p) + off += len(p) + } + return w +} + +func u64bytes(v uint64) []byte { + return common.BigToHash(new(big.Int).SetUint64(v)).Bytes()[24:] +} + +func seedPendingRead( + t *testing.T, chainApp *app.ChainApp, ctx sdk.Context, + contract common.Address, requestID *big.Int, p pendingRead, +) { + t.Helper() + k := chainApp.EVMKeeper + + k.SetState(ctx, contract, mappingSlot(requestID, slotStatus), + common.BigToHash(big.NewInt(1)).Bytes()) // PENDING + + base := mappingSlot(requestID, slotPending) + k.SetState(ctx, contract, base, packed( + p.callbackTarget.Bytes(), p.callbackSelector[:], u64bytes(p.callbackGasLimit)).Bytes()) + k.SetState(ctx, contract, slotPlus(base, 1), packed( + p.originalFunder.Bytes(), u64bytes(p.expiryHeight)).Bytes()) + k.SetState(ctx, contract, slotPlus(base, 2), packed( + p.revertRecipient.Bytes()).Bytes()) + k.SetState(ctx, contract, slotPlus(base, 3), common.BigToHash(p.callbackBudget).Bytes()) + + // escrow must cover the budget or reportCallbackGas underflows on `-=` + k.SetState(ctx, contract, common.BigToHash(big.NewInt(slotTotalEscrowed)), + common.BigToHash(p.callbackBudget).Bytes()) + + assertSeedReadBack(t, chainApp, ctx, contract, requestID, p) +} + +// assertSeedReadBack proves the slot arithmetic above by asking the contract what +// it thinks it holds. Without this the whole test could pass against zeroed state. +func assertSeedReadBack( + t *testing.T, chainApp *app.ChainApp, ctx sdk.Context, + contract common.Address, requestID *big.Int, want pendingRead, +) { + t.Helper() + viewABI := loadViewABI(t) + + status := staticCall(t, chainApp, ctx, viewABI, contract, "statusOf", requestID) + require.Equal(t, uint8(1), status[0].(uint8), "seeded status must read back as PENDING") + + got := staticCall(t, chainApp, ctx, viewABI, contract, "getPendingRead", requestID) + out := got[0].(struct { + CallbackTarget common.Address `json:"callbackTarget"` + CallbackSelector [4]byte `json:"callbackSelector"` + CallbackGasLimit uint64 `json:"callbackGasLimit"` + OriginalFunder common.Address `json:"originalFunder"` + ExpiryHeight uint64 `json:"expiryHeight"` + RevertRecipient common.Address `json:"revertRecipient"` + CallbackBudget *big.Int `json:"callbackBudget"` + }) + require.Equal(t, want.callbackTarget, out.CallbackTarget, "callbackTarget slot") + require.Equal(t, want.callbackSelector, out.CallbackSelector, "callbackSelector slot") + require.Equal(t, want.callbackGasLimit, out.CallbackGasLimit, "callbackGasLimit slot") + require.Equal(t, want.originalFunder, out.OriginalFunder, "originalFunder slot") + require.Equal(t, want.expiryHeight, out.ExpiryHeight, "expiryHeight slot") + require.Equal(t, want.revertRecipient, out.RevertRecipient, "revertRecipient slot") + require.Zero(t, want.callbackBudget.Cmp(out.CallbackBudget), "callbackBudget slot") +} + +// staticCall runs a view function and unpacks its outputs. +func staticCall( + t *testing.T, chainApp *app.ChainApp, ctx sdk.Context, parsed abi.ABI, + contract common.Address, method string, args ...interface{}, +) []interface{} { + t.Helper() + data, err := parsed.Pack(method, args...) + require.NoError(t, err) + + caller := common.HexToAddress("0x000000000000000000000000000000000000bEEF") + acc := chainApp.AccountKeeper.NewAccountWithAddress(ctx, sdk.AccAddress(caller.Bytes())) + chainApp.AccountKeeper.SetAccount(ctx, acc) + + res, err := chainApp.EVMKeeper.DerivedEVMCallWithData( + ctx, caller, &contract, data, + false /* commit: a view must not persist */, false, false, + big.NewInt(0), big.NewInt(500_000), nil, + ) + require.NoError(t, err, "%s reverted: %v", method, res) + out, err := parsed.Unpack(method, res.Ret) + require.NoError(t, err) + return out +} + +// The happy path, end to end, against the real deployed contract: a PENDING +// request is fulfilled, settled, and its consumed budget destroyed. +// +// Every other test in this package makes a call that reverts, so until this one +// existed nothing had ever executed fulfillExternalCallback or reportCallbackGas +// successfully — the settle flow was verified only by reading Solidity. +func TestLifecycle_FulfilSettleBurn_AgainstRealContract(t *testing.T) { + chainApp, ctx, _ := utils.SetAppWithValidators(t) + contract := utils.SetupUniversalCallback(t, chainApp, ctx) + k := chainApp.UcallbackKeeper + bank := chainApp.BankKeeper + + requestID := big.NewInt(0x5eed) + budget := big.NewInt(3_000_000_000_000_000) + + // An EOA target is enough: fulfillExternalCallback only needs the low-level call + // to return true, and a call to a codeless address does. What runs inside the + // callback is the app's business, not ours. + target := provisionEOA(t, chainApp, ctx, "0x00000000000000000000000000000000000c0FFE") + recipient := provisionEOA(t, chainApp, ctx, "0x00000000000000000000000000000000000Fee00") + + seedPendingRead(t, chainApp, ctx, contract, requestID, pendingRead{ + callbackTarget: target, + callbackSelector: [4]byte{0xaa, 0xbb, 0xcc, 0xdd}, + callbackGasLimit: 200_000, + originalFunder: target, + expiryHeight: uint64(ctx.BlockHeight()) + 1000, + revertRecipient: recipient, + callbackBudget: budget, + }) + + // the escrow the request is backed by must actually exist on the contract + fund(t, chainApp, ctx, sdk.AccAddress(contract.Bytes()), budget) + + supplyBefore := bank.GetSupply(ctx, pchaintypes.BaseDenom).Amount + recipientBefore := bank.GetBalance(ctx, sdk.AccAddress(recipient.Bytes()), pchaintypes.BaseDenom).Amount + + // --- fulfil, through our own keeper path ----------------------------------- + res, err := k.CallFulfillExternalCallback(ctx, hexID(requestID), &ucallbacktypes.ReadResult{ + Status: ucallbacktypes.ReadStatus_READ_STATUS_SUCCESS, + ResultData: []byte{0x01, 0x02}, + }) + require.NoError(t, err, "fulfillExternalCallback must succeed against the real contract") + require.Empty(t, res.VmError) + + viewABI := loadViewABI(t) + require.Equal(t, uint8(2), // EXECUTED + staticCall(t, chainApp, ctx, viewABI, contract, "statusOf", requestID)[0].(uint8), + "a fulfilled request must sit in EXECUTED awaiting the gas report") + + // --- settle ---------------------------------------------------------------- + cost, err := k.CallbackCost(ctx, res.GasUsed) + require.NoError(t, err) + if cost.Cmp(budget) > 0 { + cost = budget + } + + repRes, err := k.CallReportCallbackGas(ctx, hexID(requestID), cost) + require.NoError(t, err, "reportCallbackGas must succeed") + require.Empty(t, repRes.VmError) + + // The contract returns what it actually clamped the report to. Our own figure is + // recomputed rather than read back, which is only safe while the two clamps + // agree -- so assert they do. If the contract ever changes what it retains, this + // is what catches it. + burned := new(big.Int).SetBytes(repRes.Ret) + // Guard against a vacuous pass: a zero base fee would make cost, burned and the + // supply delta all zero, and every assertion below would hold trivially. + require.Positive(t, burned.Sign(), "the callback must have cost something to burn") + require.Less(t, burned.Cmp(budget), 1, "burn cannot exceed the escrowed budget") + require.Zero(t, burned.Cmp(cost), + "our burn figure must equal the contract's `burned`: got %s, contract %s", + cost, burned) + + require.Equal(t, uint8(3), // SETTLED + staticCall(t, chainApp, ctx, viewABI, contract, "statusOf", requestID)[0].(uint8)) + + // the unspent remainder must have gone back to the revert recipient + refund := new(big.Int).Sub(budget, burned) + recipientAfter := bank.GetBalance(ctx, sdk.AccAddress(recipient.Bytes()), pchaintypes.BaseDenom).Amount + require.Equal(t, sdkmath.NewIntFromBigInt(refund), recipientAfter.Sub(recipientBefore), + "the unburned budget must be refunded to revertRecipient") + + // --- burn ------------------------------------------------------------------ + require.NoError(t, k.TakeAndBurn(ctx, burned)) + + supplyAfter := bank.GetSupply(ctx, pchaintypes.BaseDenom).Amount + require.Equal(t, sdkmath.NewIntFromBigInt(burned), supplyBefore.Sub(supplyAfter), + "total supply must fall by exactly what the contract said was burned") + + // and the contract must be left holding nothing for this request + require.True(t, + bank.GetBalance(ctx, sdk.AccAddress(contract.Bytes()), pchaintypes.BaseDenom).Amount.IsZero(), + "refund + burn must together drain the request's escrow") +} + +func hexID(id *big.Int) string { return common.BigToHash(id).Hex() } + +func fund(t *testing.T, chainApp *app.ChainApp, ctx sdk.Context, to sdk.AccAddress, amt *big.Int) { + t.Helper() + coins := sdk.NewCoins(sdk.NewCoin(pchaintypes.BaseDenom, sdkmath.NewIntFromBigInt(amt))) + require.NoError(t, chainApp.BankKeeper.MintCoins(ctx, evmtypes.ModuleName, coins)) + require.NoError(t, chainApp.BankKeeper.SendCoinsFromModuleToAccount( + ctx, evmtypes.ModuleName, to, coins)) +} + +// loadViewABI parses the read-only functions used to inspect contract state. +// +// Lifted from the compiled artifact rather than hand-written: getPendingRead +// returns a 7-field packed struct, and transcribing that by hand is how the +// ReadRequested fragment ended up with its fields in the wrong order. +// +// push-chain-core-contracts, out/UniversalCallback.sol/UniversalCallback.json +func loadViewABI(t *testing.T) abi.ABI { + t.Helper() + raw, err := os.ReadFile("testdata/universal_callback_views.json") + require.NoError(t, err) + parsed, err := abi.JSON(strings.NewReader(string(raw))) + require.NoError(t, err) + return parsed +} diff --git a/test/integration/ucallback/module_account_test.go b/test/integration/ucallback/module_account_test.go new file mode 100644 index 00000000..681e4f45 --- /dev/null +++ b/test/integration/ucallback/module_account_test.go @@ -0,0 +1,77 @@ +package integrationtest + +import ( + "testing" + + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" + + evmtypes "github.com/cosmos/evm/x/vm/types" + utils "github.com/pushchain/push-chain-node/test/utils" + pchaintypes "github.com/pushchain/push-chain-node/types" + ucallbacktypes "github.com/pushchain/push-chain-node/x/ucallback/types" +) + +// The address UniversalCallback hardcodes in its access control. Derived from the +// module name, so it is fixed for the life of the chain — but derived by the real +// account keeper here, not recomputed by the test. +const expectedModuleEVMAddr = "0x07a0258D367A4A4cd9d6E4b7eEE8E7eF491CC519" + +// The module account must exist on a real app, and resolve to the address the +// contract admits. A unit test with a fake account keeper cannot show this: it +// would return whatever the fake was told to. +func TestModuleAccount_ExistsAndMatchesTheContract(t *testing.T) { + chainApp, ctx, _ := utils.SetAppWithValidators(t) + k := chainApp.UcallbackKeeper + + evmAddr, hexAddr := k.GetModuleAddress(ctx) + require.Equal(t, expectedModuleEVMAddr, hexAddr, + "UniversalCallback.sol hardcodes this; a change here breaks every fulfil and expire") + + acc := chainApp.AccountKeeper.GetModuleAccount(ctx, ucallbacktypes.ModuleName) + require.NotNil(t, acc, "the module account must be provisioned") + require.Equal(t, acc.GetAddress().Bytes(), evmAddr.Bytes(), + "the EVM address is the cosmos address's 20 bytes") +} + +// The module must hold Burner. Without it BurnCoins fails at the bank keeper, and +// no amount of unit testing with a fake bank would reveal it. +func TestModuleAccount_HasBurnerPermission(t *testing.T) { + chainApp, ctx, _ := utils.SetAppWithValidators(t) + + acc := chainApp.AccountKeeper.GetModuleAccount(ctx, ucallbacktypes.ModuleName) + modAcc, ok := acc.(sdk.ModuleAccountI) + require.True(t, ok) + require.True(t, modAcc.HasPermission(authtypes.Burner), + "x/ucallback burns consumed callback gas") + require.False(t, modAcc.HasPermission(authtypes.Minter), + "it must never be able to create supply") +} + +// The module receives the consumed budget out of UniversalCallback before burning +// it, so it must not be in the blocked set. Every maccPerms entry is blocked by +// default — this asserts the deliberate exemption is still there. +func TestModuleAccount_CanReceiveFunds(t *testing.T) { + chainApp, ctx, _ := utils.SetAppWithValidators(t) + + modAddr := authtypes.NewModuleAddress(ucallbacktypes.ModuleName) + require.False(t, chainApp.BankKeeper.BlockedAddr(modAddr), + "a blocked module account cannot be sent the escrow it must burn") + + // and prove it end to end against the real bank + funder := sdk.AccAddress(common.HexToAddress("0xBEEF").Bytes()) + coins := sdk.NewCoins(sdk.NewCoin(pchaintypes.BaseDenom, sdkmath.NewInt(1_000))) + require.NoError(t, chainApp.BankKeeper.MintCoins(ctx, evmtypes.ModuleName, coins)) + require.NoError(t, chainApp.BankKeeper.SendCoinsFromModuleToAccount( + ctx, evmtypes.ModuleName, funder, coins)) + + require.NoError(t, chainApp.BankKeeper.SendCoinsFromAccountToModule( + ctx, funder, ucallbacktypes.ModuleName, coins)) + + got := chainApp.BankKeeper.GetBalance(ctx, + authtypes.NewModuleAddress(ucallbacktypes.ModuleName), pchaintypes.BaseDenom) + require.Equal(t, sdkmath.NewInt(1_000), got.Amount) +} diff --git a/test/integration/ucallback/msg_query_test.go b/test/integration/ucallback/msg_query_test.go new file mode 100644 index 00000000..da487523 --- /dev/null +++ b/test/integration/ucallback/msg_query_test.go @@ -0,0 +1,141 @@ +package integrationtest + +import ( + "math/big" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" + + utils "github.com/pushchain/push-chain-node/test/utils" + pchaintypes "github.com/pushchain/push-chain-node/types" + ucallbackkeeper "github.com/pushchain/push-chain-node/x/ucallback/keeper" + ucallbacktypes "github.com/pushchain/push-chain-node/x/ucallback/types" + uvalidatortypes "github.com/pushchain/push-chain-node/x/uvalidator/types" +) + +// A vote from a bonded universal validator must reach the ballot and, at quorum, +// drive the read to a terminal state through the real contract. With one validator +// the first vote is already quorum, so this covers vote -> ballot -> hook -> settle +// in a single call — the wiring the unit tests stub out at every seam. +func TestVoteReadResult_SingleValidatorReachesQuorumAndSettles(t *testing.T) { + chainApp, ctx, _, validators := utils.SetAppWithMultipleValidators(t, 1) + k := chainApp.UcallbackKeeper + require.Len(t, validators, 1) + valOperator := validators[0].OperatorAddress + + require.NoError(t, chainApp.UvalidatorKeeper.AddUniversalValidator(ctx, valOperator, + uvalidatortypes.NetworkInfo{})) + + f := newReadFixture(t, chainApp, ctx, 0x31, big.NewInt(3_000_000_000_000_000), 200_000, + uint64(ctx.BlockHeight())+1000) + + valAddr, err := sdk.ValAddressFromBech32(valOperator) + require.NoError(t, err) + signer := sdk.AccAddress(valAddr).String() + + supplyBefore := chainApp.BankKeeper.GetSupply(ctx, pchaintypes.BaseDenom).Amount + + _, err = ucallbackkeeper.NewMsgServerImpl(k).VoteReadResult(ctx, &ucallbacktypes.MsgVoteReadResult{ + Signer: signer, + RequestId: f.idHex, + Result: okResult(), + }) + require.NoError(t, err, "a bonded universal validator must be allowed to vote") + + got, ok := k.GetUniversalRead(ctx, f.idHex) + require.True(t, ok) + require.Equal(t, ucallbacktypes.UniversalReadStatus_UNIVERSAL_READ_STATUS_FULFILLED, got.Status, + "quorum must carry the read all the way to FULFILLED; err=%q", got.ErrorMsg) + + // the ballot hook must have reached the real contract, not just our own state + require.Equal(t, uint8(3), // SETTLED + staticCall(t, chainApp, ctx, loadViewABI(t), f.contract, "statusOf", f.id)[0].(uint8), + "AfterBallotTerminal must drive the contract to SETTLED") + + require.True(t, + chainApp.BankKeeper.GetSupply(ctx, pchaintypes.BaseDenom).Amount.LT(supplyBefore), + "settling through a vote must burn the consumed budget") +} + +// A vote from an address that is not a universal validator must be refused. +func TestVoteReadResult_RejectsNonValidator(t *testing.T) { + chainApp, ctx, _ := utils.SetAppWithValidators(t) + k := chainApp.UcallbackKeeper + + f := newReadFixture(t, chainApp, ctx, 0x32, big.NewInt(3_000_000_000_000_000), 200_000, + uint64(ctx.BlockHeight())+1000) + + _, err := ucallbackkeeper.NewMsgServerImpl(k).VoteReadResult(ctx, &ucallbacktypes.MsgVoteReadResult{ + Signer: sdk.AccAddress([]byte("not-a-validator-addr")).String(), + RequestId: f.idHex, + Result: okResult(), + }) + require.Error(t, err, "an unbonded address must not be able to vote on a read") +} + +// UpdateParams must be gated on the governance authority. +func TestUpdateParams_AuthorityGated(t *testing.T) { + chainApp, ctx, _ := utils.SetAppWithValidators(t) + ms := ucallbackkeeper.NewMsgServerImpl(chainApp.UcallbackKeeper) + + _, err := ms.UpdateParams(ctx, &ucallbacktypes.MsgUpdateParams{ + Authority: sdk.AccAddress([]byte("definitely-not-gov")).String(), + Params: ucallbacktypes.DefaultParams(), + }) + require.Error(t, err, "only the gov authority may update params") +} + +// The deciding vote must settle the read even when the immediately preceding vote +// landed on a DIFFERENT observation. +// +// This is the case that made the ordering bug more than a single-validator quirk: +// the record tracks whichever ballot the last vote touched, so if that was a losing +// observation, the terminal hook used to look up the winning ballot and find +// nothing — quorum reached, read abandoned to the sweeper. +func TestVoteReadResult_DecidingVoteAfterALosingObservation(t *testing.T) { + const numVals = 4 // votesNeeded = (2*4)/3 + 1 = 3 + chainApp, ctx, _, validators := utils.SetAppWithMultipleValidators(t, numVals) + k := chainApp.UcallbackKeeper + + signers := make([]string, numVals) + for i, v := range validators { + require.NoError(t, chainApp.UvalidatorKeeper.AddUniversalValidator(ctx, + v.OperatorAddress, uvalidatortypes.NetworkInfo{})) + valAddr, err := sdk.ValAddressFromBech32(v.OperatorAddress) + require.NoError(t, err) + signers[i] = sdk.AccAddress(valAddr).String() + } + + f := newReadFixture(t, chainApp, ctx, 0x33, big.NewInt(3_000_000_000_000_000), 200_000, + uint64(ctx.BlockHeight())+1000) + + ms := ucallbackkeeper.NewMsgServerImpl(k) + winning := okResult() + losing := okResult() + losing.ResultData = []byte{0xff, 0xee} // a different observation => different ballot + + vote := func(signer string, r *ucallbacktypes.ReadResult) { + t.Helper() + _, err := ms.VoteReadResult(ctx, &ucallbacktypes.MsgVoteReadResult{ + Signer: signer, RequestId: f.idHex, Result: r, + }) + require.NoError(t, err) + } + + vote(signers[0], winning) // 1 of 3 on the winner + vote(signers[1], winning) // 2 of 3 + vote(signers[2], losing) // record now points at the LOSING ballot + vote(signers[3], winning) // 3 of 3 -- this must still settle + + got, ok := k.GetUniversalRead(ctx, f.idHex) + require.True(t, ok) + require.Equal(t, ucallbacktypes.UniversalReadStatus_UNIVERSAL_READ_STATUS_FULFILLED, got.Status, + "the deciding vote must settle the read regardless of what was voted before it; err=%q", + got.ErrorMsg) + require.Equal(t, winning.ResultData, got.Result.ResultData, + "the quorum observation must be the one recorded, not the last one voted") + + require.Equal(t, uint8(3), // SETTLED + staticCall(t, chainApp, ctx, loadViewABI(t), f.contract, "statusOf", f.id)[0].(uint8)) +} diff --git a/test/integration/ucallback/query_test.go b/test/integration/ucallback/query_test.go new file mode 100644 index 00000000..b7fbb01b --- /dev/null +++ b/test/integration/ucallback/query_test.go @@ -0,0 +1,164 @@ +package integrationtest + +import ( + "math/big" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" + + utils "github.com/pushchain/push-chain-node/test/utils" + pchaintypes "github.com/pushchain/push-chain-node/types" + ucallbackkeeper "github.com/pushchain/push-chain-node/x/ucallback/keeper" + ucallbacktypes "github.com/pushchain/push-chain-node/x/ucallback/types" + uvalidatortypes "github.com/pushchain/push-chain-node/x/uvalidator/types" +) + +// The query surface is what validators poll to decide what to observe and what +// operators read to see why something stalled. Wrong answers here are not cosmetic: +// AllPendingReadRequests is the work queue. +func TestQueries_ServeRealState(t *testing.T) { + chainApp, ctx, _ := utils.SetAppWithValidators(t) + k := chainApp.UcallbackKeeper + q := ucallbackkeeper.NewQuerier(k) + + require.NoError(t, k.InitGenesis(ctx, ucallbacktypes.DefaultGenesis())) + + live := newReadFixture(t, chainApp, ctx, 0x41, big.NewInt(3_000_000_000_000_000), 200_000, + uint64(ctx.BlockHeight())+1000) + + t.Run("Params", func(t *testing.T) { + res, err := q.Params(ctx, &ucallbacktypes.QueryParamsRequest{}) + require.NoError(t, err) + require.NotNil(t, res.Params) + }) + + t.Run("UniversalRead returns the record", func(t *testing.T) { + res, err := q.UniversalRead(ctx, &ucallbacktypes.QueryUniversalReadRequest{ + RequestId: live.idHex, + }) + require.NoError(t, err) + require.Equal(t, live.idHex, res.Read.Id) + }) + + t.Run("UniversalRead errors on an unknown id", func(t *testing.T) { + _, err := q.UniversalRead(ctx, &ucallbacktypes.QueryUniversalReadRequest{ + RequestId: "0xdoesnotexist", + }) + require.Error(t, err) + }) + + t.Run("AllPendingReadRequests lists the in-flight read", func(t *testing.T) { + res, err := q.AllPendingReadRequests(ctx, + &ucallbacktypes.QueryAllPendingReadRequestsRequest{}) + require.NoError(t, err) + require.True(t, containsRead(res.Reads, live.idHex), + "an unsettled read must appear in the validator work queue") + }) + + t.Run("ReadsByTx reassembles by originating tx", func(t *testing.T) { + res, err := q.ReadsByTx(ctx, &ucallbacktypes.QueryReadsByTxRequest{TxHash: "0xabc"}) + require.NoError(t, err) + require.True(t, containsRead(res.Reads, live.idHex)) + }) + + t.Run("AllAbortedReadRequests is empty until something aborts", func(t *testing.T) { + res, err := q.AllAbortedReadRequests(ctx, + &ucallbacktypes.QueryAllAbortedReadRequestsRequest{}) + require.NoError(t, err) + require.False(t, containsRead(res.Reads, live.idHex)) + }) +} + +// A settled read must leave the pending queue, or validators keep observing work +// that is already done. +func TestQueries_SettledReadLeavesThePendingQueue(t *testing.T) { + chainApp, ctx, _ := utils.SetAppWithValidators(t) + k := chainApp.UcallbackKeeper + q := ucallbackkeeper.NewQuerier(k) + require.NoError(t, k.InitGenesis(ctx, ucallbacktypes.DefaultGenesis())) + + f := newReadFixture(t, chainApp, ctx, 0x42, big.NewInt(3_000_000_000_000_000), 200_000, + uint64(ctx.BlockHeight())+1000) + + require.NoError(t, k.FulfilRead(ctx, f.universalRead( + ucallbacktypes.UniversalReadStatus_UNIVERSAL_READ_STATUS_VOTING, okResult()))) + + res, err := q.AllPendingReadRequests(ctx, &ucallbacktypes.QueryAllPendingReadRequestsRequest{}) + require.NoError(t, err) + require.False(t, containsRead(res.Reads, f.idHex), + "a fulfilled read must not still be offered as work") +} + +// The admin escape hatch is the only way an ABORTED read ever releases its escrow: +// the sweeper has given up on it and the contract admits no other caller. +func TestRetryReadExpiry_AdminOnlyAndRecovers(t *testing.T) { + chainApp, ctx, _ := utils.SetAppWithValidators(t) + k := chainApp.UcallbackKeeper + ms := ucallbackkeeper.NewMsgServerImpl(k) + + // Seed the admin BEFORE anything asserts on authorization: without it GetAdmin + // errors, and the "non-admin is refused" case below would pass on the lookup + // failure rather than on the check it claims to exercise. + admin := sdk.AccAddress([]byte("ucallback-admin-acct")).String() + require.NoError(t, chainApp.UvalidatorKeeper.Params.Set(ctx, + uvalidatortypes.Params{Admin: admin})) + + expiry := uint64(ctx.BlockHeight()) + 2 + budget := big.NewInt(2_000_000_000_000_000) + f := newReadFixture(t, chainApp, ctx, 0x43, budget, 200_000, expiry) + + // park it in ABORTED, the state nothing else can leave + aborted := f.universalRead(ucallbacktypes.UniversalReadStatus_UNIVERSAL_READ_STATUS_ABORTED, nil) + aborted.ErrorMsg = "gave up" + require.NoError(t, k.SetUniversalRead(ctx, aborted)) + + q := ucallbackkeeper.NewQuerier(k) + listed, err := q.AllAbortedReadRequests(ctx, &ucallbacktypes.QueryAllAbortedReadRequestsRequest{}) + require.NoError(t, err) + require.True(t, containsRead(listed.Reads, f.idHex), + "an abandoned read must be discoverable, or nobody knows to retry it") + + t.Run("a non-admin is refused", func(t *testing.T) { + _, err := ms.RetryReadExpiry(ctx, &ucallbacktypes.MsgRetryReadExpiry{ + Signer: sdk.AccAddress([]byte("some-random-signer!!")).String(), + RequestId: f.idHex, + }) + require.Error(t, err, "only the uvalidator admin may drive the escape hatch") + }) + + t.Run("the admin recovers the escrow", func(t *testing.T) { + past := ctx.WithBlockHeight(int64(expiry) + 1) + recipientBefore := chainApp.BankKeeper.GetBalance(past, + sdk.AccAddress(f.recipient.Bytes()), pchaintypes.BaseDenom).Amount + + _, err := ms.RetryReadExpiry(past, &ucallbacktypes.MsgRetryReadExpiry{ + Signer: admin, RequestId: f.idHex, + }) + require.NoError(t, err) + + got, _ := k.GetUniversalRead(past, f.idHex) + require.Equal(t, ucallbacktypes.UniversalReadStatus_UNIVERSAL_READ_STATUS_EXPIRED, got.Status, + "a successful retry must retire the read; err=%q", got.ErrorMsg) + + recipientAfter := chainApp.BankKeeper.GetBalance(past, + sdk.AccAddress(f.recipient.Bytes()), pchaintypes.BaseDenom).Amount + require.True(t, recipientAfter.GT(recipientBefore), + "the whole point of the hatch is that the funder gets paid") + + // and it must drop off the aborted list + after, err := q.AllAbortedReadRequests(past, + &ucallbacktypes.QueryAllAbortedReadRequestsRequest{}) + require.NoError(t, err) + require.False(t, containsRead(after.Reads, f.idHex)) + }) +} + +func containsRead(reads []ucallbacktypes.UniversalRead, id string) bool { + for _, r := range reads { + if r.Id == id { + return true + } + } + return false +} diff --git a/test/integration/ucallback/testdata/request_external_read_self.json b/test/integration/ucallback/testdata/request_external_read_self.json new file mode 100644 index 00000000..3f2f03fe --- /dev/null +++ b/test/integration/ucallback/testdata/request_external_read_self.json @@ -0,0 +1,85 @@ +[ + { + "type": "function", + "name": "requestExternalReadSelf", + "inputs": [ + { + "name": "spec", + "type": "tuple", + "internalType": "struct ReadSpec", + "components": [ + { + "name": "account", + "type": "tuple", + "internalType": "struct UniversalAccountId", + "components": [ + { + "name": "chainNamespace", + "type": "string", + "internalType": "string" + }, + { + "name": "chainId", + "type": "string", + "internalType": "string" + }, + { + "name": "owner", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "query", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "minConfirmations", + "type": "uint16", + "internalType": "uint16" + }, + { + "name": "blockNumber", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "expiryPushChainHeight", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "maxFee", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "revertRecipient", + "type": "address", + "internalType": "address" + } + ] + }, + { + "name": "callbackSelector", + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "callbackGasLimit", + "type": "uint64", + "internalType": "uint64" + } + ], + "outputs": [ + { + "name": "requestId", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "payable" + } +] \ No newline at end of file diff --git a/test/integration/ucallback/testdata/universal_callback_views.json b/test/integration/ucallback/testdata/universal_callback_views.json new file mode 100644 index 00000000..b5403ffe --- /dev/null +++ b/test/integration/ucallback/testdata/universal_callback_views.json @@ -0,0 +1,90 @@ +[ + { + "type": "function", + "name": "getPendingRead", + "inputs": [ + { + "name": "requestId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "tuple", + "internalType": "struct PendingRead", + "components": [ + { + "name": "callbackTarget", + "type": "address", + "internalType": "address" + }, + { + "name": "callbackSelector", + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "callbackGasLimit", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "originalFunder", + "type": "address", + "internalType": "address" + }, + { + "name": "expiryHeight", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "revertRecipient", + "type": "address", + "internalType": "address" + }, + { + "name": "callbackBudget", + "type": "uint256", + "internalType": "uint256" + } + ] + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "statusOf", + "inputs": [ + { + "name": "requestId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "uint8", + "internalType": "enum RequestStatus" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "totalEscrowed", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + } +] \ No newline at end of file diff --git a/test/utils/bytecode.go b/test/utils/bytecode.go index 01a812a3..3a892874 100644 --- a/test/utils/bytecode.go +++ b/test/utils/bytecode.go @@ -100,3 +100,17 @@ const VAULT_PC20_TEST_BYTECODE = "6080806040526004361015610012575f80fd5b5f3560e0 // MOCK_ERC20_BYTECODE is a minimal ERC20 (public mint) used as the PC20 source token so // VaultPC20 can hold a real balance for recordLock/unlock. const MOCK_ERC20_BYTECODE = "6080806040526004361015610012575f80fd5b5f3560e01c908163059cbd9b146111795750806306fdde03146110a0578063095ea7b31461105c57806316320dad14610fa057806318160ddd14610f6557806323b872dd14610dab578063313ce56714610d6d57806338b616c114610ceb57806340c10f1914610c0d57806342966c6814610ba757806347af995714610b215780635a7cc05014610b0a57806370a0823114610aa857806375e3661e146109fe5780637a8f159e146109425780637e4831d3146108ff5780638936a91f1461087d5780638e64a7ef146107e857806395d89b411461069f5780639dc29fac14610619578063a9059cbb14610570578063ae200322146104ee578063d684534e146104ab578063da8fbf2a14610424578063dbac26e914610166578063dd62ed3e14610380578063e6194af9146102c2578063f9f92be414610215578063fb2cb34e146101d25763fe575a8714610166575f80fd5b346101ce5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101ce5773ffffffffffffffffffffffffffffffffffffffff6101b261126a565b165f526006602052602060ff60405f2054166040519015158152f35b5f80fd5b346101ce575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101ce57602060ff60055460081c166040519015158152f35b346101ce5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101ce577fffa4e6181777692565cf28528fc88fd1516ea86b56da075235fa575af6a4b855602073ffffffffffffffffffffffffffffffffffffffff61028461126a565b16805f526006825260405f2060017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825416179055604051908152a1005b346101ce575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101ce5761037c6102fe600254611795565b610370602e60405180937f546f74616c20537570706c793a20000000000000000000000000000000000000602083015261034181518092602086860191016111ff565b810103017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081018352826112ff565b60405191829182611220565b0390f35b346101ce5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101ce576103b761126a565b6024359073ffffffffffffffffffffffffffffffffffffffff821682036101ce5773ffffffffffffffffffffffffffffffffffffffff165f52600160205273ffffffffffffffffffffffffffffffffffffffff60405f2091165f52602052602060405f2054604051908152f35b346101ce575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101ce57620100007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff60055416176005557fee9b45d4bbbf616909699035be16f077b7459c8d4db74944d4e27d84f15faf346020604051338152a1005b346101ce575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101ce57602060ff60055460181c166040519015158152f35b346101ce575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101ce577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff600554166005557f4edc83796ddd13f7381b8c91ffbca02176782693577083e23486400548aaa8a16020604051338152a1005b346101ce5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101ce5761060e6105aa61126a565b6105bc60ff60055460081c161561136d565b335f5260066020526105d560ff60405f205416156113d2565b73ffffffffffffffffffffffffffffffffffffffff81165f52600660205261060460ff60405f20541615611437565b6024359033611997565b602060405160018152f35b346101ce5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101ce5761069d61065361126a565b61066560ff60055460181c16156114c2565b73ffffffffffffffffffffffffffffffffffffffff81165f52600660205261069460ff60405f20541615611527565b60243590611685565b005b346101ce575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101ce576040515f6004548060011c906001811680156107de575b6020831081146107b15782855290811561076f5750600114610711575b61037c83610370818503826112ff565b91905060045f527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b915f905b80821061075557509091508101602001610370610701565b91926001816020925483858801015201910190929161073d565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660208086019190915291151560051b840190910191506103709050610701565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b91607f16916106e4565b346101ce5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101ce5761081f61126a565b6024359073ffffffffffffffffffffffffffffffffffffffff81165f525f60205260405f20548083115f146108615761085b9061069d936115b2565b906115ec565b80831061086a57005b61069d92610877916115b2565b90611685565b346101ce575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101ce577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff600554166005557f27b779563480879c8e2872999840b721537eb09dccf94115a2276ca341cdbb526020604051338152a1005b346101ce575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101ce57602060ff60055460101c166040519015158152f35b346101ce5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101ce5761097961126a565b5060846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f4d6f636b45524332303a2073696d756c6174656420617070726f76616c20666160448201527f696c7572650000000000000000000000000000000000000000000000000000006064820152fd5b346101ce5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101ce577f7534c63860313c46c473e4e98328f37017e9674e2162faf1a3ad7a96236c3b7b602073ffffffffffffffffffffffffffffffffffffffff610a6d61126a565b16805f526006825260405f207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008154169055604051908152a1005b346101ce5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101ce5773ffffffffffffffffffffffffffffffffffffffff610af461126a565b165f525f602052602060405f2054604051908152f35b346101ce5761069d610b1b3661128d565b9161191a565b346101ce575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101ce576101007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff60055416176005557f483d42b2ec355eefc30508020d123de3c2fca2f0d6f8e751f98449099242b76b6020604051338152a1005b346101ce5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101ce57610be860ff60055460181c16156114c2565b335f526006602052610c0160ff60405f20541615611527565b61069d60043533611685565b346101ce5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101ce57610c4461126a565b60ff60055460101c16610c8d578073ffffffffffffffffffffffffffffffffffffffff61069d92165f526006602052610c8460ff60405f20541615611437565b602435906115ec565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f4d6f636b45524332303a206d696e74696e6720697320706175736564000000006044820152fd5b346101ce575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101ce577fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffff600554166005557fa854ea59322d4b14774ee2cca1187710017c50686e8af5272b10a6aa296771f16020604051338152a1005b346101ce575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101ce57602060ff60055416604051908152f35b346101ce57610db93661128d565b90610dcc60ff60055460081c161561136d565b73ffffffffffffffffffffffffffffffffffffffff831692835f526006602052610dfd60ff60405f205416156113d2565b73ffffffffffffffffffffffffffffffffffffffff82165f526006602052610e2c60ff60405f20541615611437565b835f52600160205260405f2073ffffffffffffffffffffffffffffffffffffffff33165f5260205260405f20547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8110610e8c575b5061060e9350611997565b838110610f31578415610f05573315610ed95761060e945f52600160205260405f2073ffffffffffffffffffffffffffffffffffffffff33165f526020528360405f209103905584610e81565b7f94280d62000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b7fe602df05000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b83907ffb8f41b2000000000000000000000000000000000000000000000000000000005f523360045260245260445260645ffd5b346101ce575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101ce576020600254604051908152f35b346101ce5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101ce57610fd761126a565b5060846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f4d6f636b45524332303a2073696d756c61746564207472616e7366657220666160448201527f696c7572650000000000000000000000000000000000000000000000000000006064820152fd5b346101ce5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101ce5761060e61109661126a565b602435903361191a565b346101ce575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101ce576040515f6003548060011c9060018116801561116f575b6020831081146107b15782855290811561076f57506001146111115761037c83610370818503826112ff565b91905060035f527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b915f905b80821061115557509091508101602001610370610701565b91926001816020925483858801015201910190929161113d565b91607f16916110e5565b346101ce575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101ce5760207f1c734234efe17d5f92978089797af73272adfda26b905f6818b2591f162a9fc89163010000007fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffff6005541617600555338152a1005b5f5b8381106112105750505f910152565b8181015183820152602001611201565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f6040936020845261126381518092816020880152602088880191016111ff565b0116010190565b6004359073ffffffffffffffffffffffffffffffffffffffff821682036101ce57565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc60609101126101ce5760043573ffffffffffffffffffffffffffffffffffffffff811681036101ce579060243573ffffffffffffffffffffffffffffffffffffffff811681036101ce579060443590565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761134057604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b1561137457565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f4d6f636b45524332303a207472616e73666572732061726520706175736564006044820152fd5b156113d957565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602060248201527f4d6f636b45524332303a2073656e64657220697320626c61636b6c69737465646044820152fd5b1561143e57565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f4d6f636b45524332303a20726563697069656e7420697320626c61636b6c697360448201527f74656400000000000000000000000000000000000000000000000000000000006064820152fd5b156114c957565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f4d6f636b45524332303a206275726e696e6720697320706175736564000000006044820152fd5b1561152e57565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f4d6f636b45524332303a206163636f756e7420697320626c61636b6c6973746560448201527f64000000000000000000000000000000000000000000000000000000000000006064820152fd5b919082039182116115bf57565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b73ffffffffffffffffffffffffffffffffffffffff1690811561165957600254908082018092116115bf5760207fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef915f9360025584845283825260408420818154019055604051908152a3565b7fec442f05000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b90919073ffffffffffffffffffffffffffffffffffffffff16801561172f57805f525f60205260405f20548381106116fc576020845f94957fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef938587528684520360408620558060025403600255604051908152a3565b91507fe450d38c000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b7f96c6fd1e000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b67ffffffffffffffff811161134057601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b80156118de575f81805b6118a857506117ad8161175b565b906117bb60405192836112ff565b8082527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe06117e88261175b565b013660208401375b809280156118a1577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82019182116115bf578193600a820660300192836030116115bf578451111561187457601f7fff00000000000000000000000000000000000000000000000000000000000000600a9460f81b165f1a918501015304916117f0565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5050905090565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146115bf576001600a910191048061179f565b506040516118ed6040826112ff565b600181527f3000000000000000000000000000000000000000000000000000000000000000602082015290565b73ffffffffffffffffffffffffffffffffffffffff16908115610f055773ffffffffffffffffffffffffffffffffffffffff16918215610ed95760207f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591835f526001825260405f20855f5282528060405f2055604051908152a3565b73ffffffffffffffffffffffffffffffffffffffff1690811561172f5773ffffffffffffffffffffffffffffffffffffffff1691821561165957815f525f60205260405f2054818110611a2f57817fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92602092855f525f84520360405f2055845f525f825260405f20818154019055604051908152a3565b827fe450d38c000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffdfea26469706673582212209da2240b40485a53b19910fadd0fb269d5517302c490c50b8e7bf1af1871ca7464736f6c634300081a0033" + +const UNIVERSAL_CALLBACK_BYTECODE = "608080604052600436101561001c575b50361561001a575f80fd5b005b5f3560e01c90816301ffc9a7146132b557508063022d63fb1461327a578063049bf04c1461313c57806309149020146130b35780630aa6220b14612f53578063248a9ca314612ee35780632b27043e14612d7e5780632f2ff15d14612cfd57806336568abe14612af65780633f22ef67146127c75780633f4ba83a146126a057806349ef9ed4146124385780635c975abb146123d9578063634e93da14612226578063649a5ec714611f125780636b410aa914611ec157806372767171146115025780637cd88fc6146114b25780638421aee5146111d35780638456cb59146110aa57806384ef8ffc146110a55780638da5cb5b146110a557806391d14854146110115780639a52d1d214610fd0578063a1eda53c14610f32578063a217fddf14610efa578063ad35efd414610e79578063b1ca7df014610db7578063bc6939c914610d49578063c0c53b8b14610918578063cc8463c8146108d0578063cefc14291461071b578063cf6eefb714610672578063d547741f146105c4578063d602b9fd1461050e578063dca9f0681461044e578063df1734dd146103f6578063e63ab1e91461039e578063e83c0d141461021f5763f9168231146101e0575f61000f565b3461021b575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261021b576020600654604051908152f35b5f80fd5b3461021b5760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261021b5760043567ffffffffffffffff811161021b5761026e9036906004016133ea565b9060243567ffffffffffffffff811161021b5761028f9036906004016133ea565b6044939193359081151580920361021b57335f9081527f8400c436bad92365f13837f68b2c73aae69f413323a30e8637a4bf36ec9c0c5a602052604090205460ff1615610376577fb5faed8166cdc2f56c7918fb9d203a9277482cfd7fa4e9504b1bc24ff2bcabc09461036b9161031b6040518688823760208188810160058152030190208284613736565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0081541660ff861617905561035d604051968796606088526060880191613674565b918583036020870152613674565b9060408301520390a1005b7f8dfa73db000000000000000000000000000000000000000000000000000000005f5260045ffd5b3461021b575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261021b5760206040517f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a8152f35b3461021b575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261021b5760206040517f8560dd4a88735ec0892d189314f1b42fca842bd42705b1317b77b4affbe666dd8152f35b3461021b57602061045e3661349d565b9392909173ffffffffffffffffffffffffffffffffffffffff5f5416916104b4604051968795869485947fc2d5c08c0000000000000000000000000000000000000000000000000000000086526004860161374f565b03915afa8015610503575f906104d0575b602090604051908152f35b506020813d6020116104fb575b816104ea60209383613556565b8101031261021b57602090516104c5565b3d91506104dd565b6040513d5f823e3d90fd5b3461021b575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261021b576105446139ef565b7feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d869840080547fffffffffffff0000000000000000000000000000000000000000000000000000811690915560a01c65ffffffffffff1661059e57005b7f8886ebfc4259abdbc16601dd8fb5678e54878f47b3c34836cfc51154a96051095f80a1005b3461021b5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261021b576004356105fe6133a4565b811561064a578161064561064061001a945f527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800602052600160405f20015490565b613a57565b613f7f565b7f3fc3c27a000000000000000000000000000000000000000000000000000000005f5260045ffd5b3461021b575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261021b57604065ffffffffffff6106f57feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d8698400549065ffffffffffff73ffffffffffffffffffffffffffffffffffffffff83169260a01c1690565b73ffffffffffffffffffffffffffffffffffffffff849392935193168352166020820152f35b3461021b575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261021b577feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d86984005473ffffffffffffffffffffffffffffffffffffffff1633036108a4577feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d86984005460a081901c65ffffffffffff169073ffffffffffffffffffffffffffffffffffffffff168115801561089a575b61086e576108249061081e73ffffffffffffffffffffffffffffffffffffffff7feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d86984015416613eb5565b50613cbd565b507feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d869840080547fffffffffffff0000000000000000000000000000000000000000000000000000169055005b507f19ca5ebb000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b50428210156107d6565b7fc22c8022000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b3461021b575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261021b576020610908613978565b65ffffffffffff60405191168152f35b3461021b5760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261021b5761094f6133c7565b6109576133a4565b6044359073ffffffffffffffffffffffffffffffffffffffff821680830361021b577ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460ff8160401c16159467ffffffffffffffff821680159081610d41575b6001149081610d37575b159081610d2e575b50610d0657818660017fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000073ffffffffffffffffffffffffffffffffffffffff9516177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0055610cb1575b50169081158015610c93575b8015610c8b575b610c6357610a5261409a565b610a5a61409a565b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055610a8661409a565b610a8e61409a565b15610c3757610b4c73ffffffffffffffffffffffffffffffffffffffff937c015180000000000000000000000000000000000000000000000000000079ffffffffffffffffffffffffffffffffffffffffffffffffffff7feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d86984005416177feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d869840055610b3481613cbd565b50610b3d61409a565b610b4681613d86565b50613db0565b507fffffffffffffffffffffffff00000000000000000000000000000000000000005f5416175f55167fffffffffffffffffffffffff00000000000000000000000000000000000000006001541617600155610ba457005b7fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054167ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602060405160018152a1005b7fc22c8022000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b7fd671aae7000000000000000000000000000000000000000000000000000000005f5260045ffd5b508015610a46565b5073ffffffffffffffffffffffffffffffffffffffff831615610a3f565b7fffffffffffffffffffffffffffffffffffffffffffffff0000000000000000001668010000000000000001177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005586610a33565b7ff92ee8a9000000000000000000000000000000000000000000000000000000005f5260045ffd5b905015876109ca565b303b1591506109c2565b8791506109b8565b3461021b575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261021b57602060405173ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000007a0258d367a4a4cd9d6e4b7eee8e7ef491cc519168152f35b3461021b5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261021b5760043567ffffffffffffffff811161021b57610e069036906004016135d1565b60243567ffffffffffffffff811161021b57610e6460208093610e4782610e3360ff9636906004016135d1565b928160405193828580945193849201613617565b810160058152030190208260405194838680955193849201613617565b82019081520301902054166040519015158152f35b3461021b5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261021b576004355f52600260205260ff60405f2054166040516005821015610ecd576020918152f35b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b3461021b575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261021b5760206040515f8152f35b3461021b575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261021b577feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d8698401548060d01c9081151580610fc6575b15610fbd5760a01c65ffffffffffff165b6040805165ffffffffffff928316815292909116602083015290f35b50505f80610fa1565b5042821015610f90565b3461021b57602060ff61100582610fe63661349d565b925f949194508260405193849283378101600581520301902091613736565b54166040519015158152f35b3461021b5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261021b576110486133a4565b6004355f527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680060205273ffffffffffffffffffffffffffffffffffffffff60405f2091165f52602052602060ff60405f2054166040519015158152f35b61342d565b3461021b575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261021b57335f9081527f75442b0a96088b5456bc4ed01394c96a4feec0f883c9494257d76b96ab1c9b6b602052604090205460ff16156111ab57611116613c6a565b60017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff007fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033005416177fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586020604051338152a1005b7f5c427cd9000000000000000000000000000000000000000000000000000000005f5260045ffd5b3461021b5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261021b5760043560243573ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000007a0258d367a4a4cd9d6e4b7eee8e7ef491cc51916330361148a5761124d613add565b815f52600260205260ff60405f205416916005831015610ecd57600283036114555760209250805f52600383527fe1e66ec2c81f3e0a3a7507a5cccd18645e3f605403ed0e19b9e605c5516d5493606060405f2093604051946112af8661350d565b805473ffffffffffffffffffffffffffffffffffffffff811687527fffffffff000000000000000000000000000000000000000000000000000000008160401b168888015260c01c604087015267ffffffffffffffff600182015473ffffffffffffffffffffffffffffffffffffffff81168589015260a01c16608087015260c0600373ffffffffffffffffffffffffffffffffffffffff6002840154169260a0890193845201549601908682528683115f14611447576113d66113738880613638565b92875f5260028a5260405f2060037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825416179055875f5260038a526113cd60405f2060035f918281558260018201558260028201550155565b51600654613638565b600655818061141f575b505060405191825285878301526040820152a260017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055604051908152f35b73ffffffffffffffffffffffffffffffffffffffff61144092511687613bad565b87816113e0565b6113d6611373848099613638565b90507f0a8c14ec000000000000000000000000000000000000000000000000000000005f52600452602452600260445260645ffd5b7f023b1c9f000000000000000000000000000000000000000000000000000000005f5260045ffd5b3461021b575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261021b57602073ffffffffffffffffffffffffffffffffffffffff5f5416604051908152f35b60607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261021b5760043567ffffffffffffffff811161021b578060040160e07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc833603011261021b57602435907fffffffff00000000000000000000000000000000000000000000000000000000821680920361021b5760443567ffffffffffffffff811680910361021b576115b9613c6a565b6115c1613add565b6115d46115ce83806136b2565b806136e5565b9050158015611eab575b8015611e8b575b611e63576115f660248501836136e5565b905015611e3b57604484013561ffff811680910361021b57600111611e135760ff61165b60206116296115ce86806136b2565b91908260405193849283378101600581520301902061165561164b86806136b2565b60208101906136e5565b90613736565b5416611dbc576064840167ffffffffffffffff61167782613779565b1615908115611ce8575b50611cc0576084840161169381613779565b67ffffffffffffffff4391161115611c985760c4850173ffffffffffffffffffffffffffffffffffffffff6116c78261378e565b1615611c70578215611c4857620f42408311611c155773ffffffffffffffffffffffffffffffffffffffff5f54169560206117056115ce87806136b2565b9861171c61171389806136b2565b848101906136e5565b9a90926117586040519c8d95869485947fc2d5c08c0000000000000000000000000000000000000000000000000000000086526004860161374f565b03915afa968715610503575f97611be1575b50863410611bb15760a40135803411611b8257506040516020810190602082526117c78161179b60408201896137ff565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101835282613556565b519020600454907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8214611b555781600160039301600455604051906020820192468452436040840152306060840152608083015260a082015260a0815261183060c082613556565b5190209573ffffffffffffffffffffffffffffffffffffffff61189a6118946118598b34613638565b968a5f52600260205260405f2060017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825416179055613779565b9461378e565b604051946118a78661350d565b338652602086019384526040860190888252606087019133835267ffffffffffffffff60808901921682528460a089019416845260c08801958987528c5f5287602052858060405f209a5116167fffffffffffffffffffffffff00000000000000000000000000000000000000008a541617895551908577ffffffff0000000000000000000000000000000000000000807fffffffffffffffff0000000000000000000000000000000000000000000000008c54945160c01b169460401c1616911617178755838060018901935116167fffffffffffffffffffffffff0000000000000000000000000000000000000000835416178255517fffffffff0000000000000000ffffffffffffffffffffffffffffffffffffffff7bffffffffffffffff000000000000000000000000000000000000000083549260a01b169116179055511673ffffffffffffffffffffffffffffffffffffffff6002850191167fffffffffffffffffffffffff000000000000000000000000000000000000000082541617905551910155600654818101809111611b5557600655611a566040519360a0855260a08501906137ff565b9160208401523460408401528460608401526080830152827f4eff8080da7bb648f5eed3bfbb21041b583987e36c6808f5483bd6cf9e16016033938033940390a481611acc575b60209060017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055604051908152f35b73ffffffffffffffffffffffffffffffffffffffff600154165f80808086855af1611af5613645565b5015611b2d57817fc45f61dba651e5041f5af1d5515e835ad0a433dcae1afac75b22e7c609a771bf60208095604051908152a3611a9d565b7f90b8ec18000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b7fce7d070c000000000000000000000000000000000000000000000000000000005f523460045260245260445ffd5b867fa458261b000000000000000000000000000000000000000000000000000000005f523460045260245260445ffd5b9096506020813d602011611c0d575b81611bfd60209383613556565b8101031261021b5751958761176a565b3d9150611bf0565b827f91a0023e000000000000000000000000000000000000000000000000000000005f52600452620f424060245260445ffd5b7f1a868e51000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f17bf3e71000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f5958895b000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f4e47846c000000000000000000000000000000000000000000000000000000005f5260045ffd5b611d5c9150611cf690613779565b602073ffffffffffffffffffffffffffffffffffffffff5f5416611d1d6115ce87806136b2565b6040929192518096819482937f68c70c9e0000000000000000000000000000000000000000000000000000000084528760048501526024840191613674565b03915afa918215610503575f92611d80575b5067ffffffffffffffff161185611681565b9091506020813d602011611db4575b81611d9c60209383613556565b8101031261021b57519067ffffffffffffffff611d6e565b3d9150611d8f565b61164b82611e0f611ddc611dd36115ce84806136b2565b949093806136b2565b906040519485947fcdc3ac140000000000000000000000000000000000000000000000000000000086526004860161374f565b0390fd5b7f7752aa44000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f63d15d83000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f355e4a0c000000000000000000000000000000000000000000000000000000005f5260045ffd5b50611ea3611e9983806136b2565b60408101906136e5565b9050156115e5565b50611eb961164b83806136b2565b9050156115de565b3461021b575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261021b57602073ffffffffffffffffffffffffffffffffffffffff60015416604051908152f35b3461021b5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261021b5760043565ffffffffffff81169081810361021b57611f5d6139ef565b611f6642614052565b9165ffffffffffff611f76613978565b16808211156121ec57507ff1038c18cf84a56e432fdbfaf746924b7ea511dfe03a6506a0ceba4888788d9b9265ffffffffffff826206978080611fc3951091180262069780181690613c4c565b907feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d8698401548060d01c8061212b575b5050612080817fffffffffffff000000000000ffffffffffffffffffffffffffffffffffffffff79ffffffffffff00000000000000000000000000000000000000007feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d8698401549260a01b169116177feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d869840155565b61210e8279ffffffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffff00000000000000000000000000000000000000000000000000007feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d8698401549260d01b169116177feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d869840155565b6040805165ffffffffffff928316815292909116602083015290a1005b4211156121c25779ffffffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffff00000000000000000000000000000000000000000000000000007feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d8698400549260301b169116177feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d8698400555b8380611ff0565b507f2b1fa2edafe6f7b9e97c1a9e0c3660e645beb2dcaa2d45bdbf9beaf5472e1ec55f80a16121bb565b0365ffffffffffff8111611b55577ff1038c18cf84a56e432fdbfaf746924b7ea511dfe03a6506a0ceba4888788d9b92611fc39190613c4c565b3461021b5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261021b5761225d6133c7565b6122656139ef565b7f3377dc44241e779dd06afab5b788a35ca5f3b778836e2990bdb26a2a4b2e5ed660206122a261229442614052565b61229c613978565b90613c4c565b65ffffffffffff73ffffffffffffffffffffffffffffffffffffffff61230a7feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d8698400549065ffffffffffff73ffffffffffffffffffffffffffffffffffffffff83169260a01c1690565b96905016947feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d869840054867fffffffffffff000000000000000000000000000000000000000000000000000079ffffffffffff00000000000000000000000000000000000000008660a01b16921617177feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d869840055166123b0575b65ffffffffffff60405191168152a2005b7f8886ebfc4259abdbc16601dd8fb5678e54878f47b3c34836cfc51154a96051095f80a161239f565b3461021b575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261021b57602060ff7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f0330054166040519015158152f35b3461021b5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261021b5760043573ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000007a0258d367a4a4cd9d6e4b7eee8e7ef491cc51916330361148a576124af613add565b6124b881613b54565b805f52600360205260405f2090604051916124d28361350d565b805473ffffffffffffffffffffffffffffffffffffffff811684527fffffffff000000000000000000000000000000000000000000000000000000008160401b16602085015260c01c604084015267ffffffffffffffff600182015473ffffffffffffffffffffffffffffffffffffffff8116606086015260a01c1680608085015260c0600373ffffffffffffffffffffffffffffffffffffffff6002850154169360a0870194855201549401938452431061267857602073ffffffffffffffffffffffffffffffffffffffff7fcaf80ef6ca16ef1764d539cd743c3c61fdd7cf992673263af2f51ba97c4bdf9792845f526002835260405f2060047fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825416179055845f526003835261261a60405f2060035f918281558260018201558260028201550155565b6126278651600654613638565b600655855180612664575b5051169351604051908152a360017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055005b612672908383511687613bad565b86612632565b7fdbc3decb000000000000000000000000000000000000000000000000000000005f5260045ffd5b3461021b575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261021b57335f9081527f75442b0a96088b5456bc4ed01394c96a4feec0f883c9494257d76b96ab1c9b6b602052604090205460ff16156111ab577fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033005460ff81161561279f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00167fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa6020604051338152a1005b7f8dfc202b000000000000000000000000000000000000000000000000000000005f5260045ffd5b3461021b5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261021b5760043560243567ffffffffffffffff811161021b576128199036906004016133ea565b9073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000007a0258d367a4a4cd9d6e4b7eee8e7ef491cc51916330361148a5761285f613add565b61286883613b54565b825f52600360205260405f206040516128808161350d565b81549173ffffffffffffffffffffffffffffffffffffffff8316808352600360208401927fffffffff000000000000000000000000000000000000000000000000000000008660401b168452604085019560c01c865267ffffffffffffffff600182015473ffffffffffffffffffffffffffffffffffffffff8116606088015260a01c16608086015273ffffffffffffffffffffffffffffffffffffffff60028201541660a0860152015460c084015215612ace575f92837fffffffff0000000000000000000000000000000000000000000000000000000067ffffffffffffffff73ffffffffffffffffffffffffffffffffffffffff83968b855260026020526040852060027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082541617905551169351169351169160405160208101938452896024820152604060448201526129e08161179b606482018c8c613674565b5193f1916129ec613645565b9215612a56577fd6a6c23b749728f0fce8f6f7a34e8d7eb9e376a5d66bf118ec42a4072cef2f049250612a2c604051928392602084526020840191613674565b0390a25b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055005b5050601f60407f3fd354b63e80a8f37a7fe5f2fbe6bd357a9c5fe4396581e75456e59740834873927fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0825193849260208452612ac18151809281602088015260208888019101613617565b01168101030190a2612a30565b7ff279b296000000000000000000000000000000000000000000000000000000005f5260045ffd5b3461021b5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261021b57600435612b306133a4565b811580612ca7575b612b8b575b3373ffffffffffffffffffffffffffffffffffffffff821603612b635761001a91613f7f565b7f6697b232000000000000000000000000000000000000000000000000000000005f5260045ffd5b7feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d86984005465ffffffffffff60a082901c169073ffffffffffffffffffffffffffffffffffffffff1615801590612c97575b8015612c85575b612c5157507fffffffffffff000000000000ffffffffffffffffffffffffffffffffffffffff7feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d869840054167feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d869840055612b3d565b65ffffffffffff907f19ca5ebb000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b504265ffffffffffff82161015612be1565b5065ffffffffffff811615612bda565b5073ffffffffffffffffffffffffffffffffffffffff7feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d8698401541673ffffffffffffffffffffffffffffffffffffffff821614612b38565b3461021b5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261021b57600435612d376133a4565b811561064a5781612d7961064061001a945f527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800602052600160405f20015490565b613dda565b3461021b5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261021b575f60c0604051612dbc8161350d565b8281528260208201528260408201528260608201528260808201528260a082015201526004355f52600360205260e060405f20604051612dfb8161350d565b73ffffffffffffffffffffffffffffffffffffffff8167ffffffffffffffff845483808216968785528360208601937fffffffff000000000000000000000000000000000000000000000000000000008160401b168552604087019060c01c81527fffffffff0000000000000000000000000000000000000000000000000000000060018401549560c0600360608b0196888a1688528660808d019a60a01c168a5260a0896002830154169c019b8c5201549b019a8b526040519b8c52511660208b0152511660408901525116606087015251166080850152511660a08301525160c0820152f35b3461021b5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261021b576020612f4b6004355f527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800602052600160405f20015490565b604051908152f35b3461021b575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261021b57612f896139ef565b7feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d8698401548060d01c80612ff2575b7feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d8698401805473ffffffffffffffffffffffffffffffffffffffff169055005b4211156130895779ffffffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffff00000000000000000000000000000000000000000000000000007feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d8698400549260301b169116177feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d8698400555b8080612fb5565b507f2b1fa2edafe6f7b9e97c1a9e0c3660e645beb2dcaa2d45bdbf9beaf5472e1ec55f80a1613082565b3461021b5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261021b576004355f52600260205260ff60405f205416600581101580610ecd5760028214908115613130575b811561311e575b6020826040519015158152f35b9050610ecd5760046020911482613111565b5050600381145f61310a565b3461021b5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261021b5760043573ffffffffffffffffffffffffffffffffffffffff811680910361021b576024356131976139ef565b811561325257801561322a576131b04760065490613638565b8082116131fb57505f80808084865af16131c8613645565b5015611b2d5760207f0c7fbc93fbefdd9d47c9cc2cc78b6ee1db0a897966a4f63cad22de5dc848a6a091604051908152a2005b907fb7ddd88b000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f1f2a2005000000000000000000000000000000000000000000000000000000005f5260045ffd5b7fd92e233d000000000000000000000000000000000000000000000000000000005f5260045ffd5b3461021b575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261021b576020604051620697808152f35b3461021b5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261021b57600435907fffffffff00000000000000000000000000000000000000000000000000000000821680920361021b57817f314987860000000000000000000000000000000000000000000000000000000060209314908115613347575b5015158152f35b7f7965db0b0000000000000000000000000000000000000000000000000000000081149150811561337a575b5083613340565b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501483613373565b6024359073ffffffffffffffffffffffffffffffffffffffff8216820361021b57565b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361021b57565b9181601f8401121561021b5782359167ffffffffffffffff831161021b576020838186019501011161021b57565b359067ffffffffffffffff8216820361021b57565b3461021b575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261021b57602073ffffffffffffffffffffffffffffffffffffffff7feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d86984015416604051908152f35b60407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc82011261021b5760043567ffffffffffffffff811161021b57816134e6916004016133ea565b929092916024359067ffffffffffffffff821161021b57613509916004016133ea565b9091565b60e0810190811067ffffffffffffffff82111761352957604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761352957604052565b67ffffffffffffffff811161352957601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b81601f8201121561021b578035906135e882613597565b926135f66040519485613556565b8284526020838301011161021b57815f926020809301838601378301015290565b5f5b8381106136285750505f910152565b8181015183820152602001613619565b91908203918211611b5557565b3d1561366f573d9061365682613597565b916136646040519384613556565b82523d5f602084013e565b606090565b601f82602094937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe093818652868601375f8582860101520116010190565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa18136030182121561021b570190565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18136030182121561021b570180359067ffffffffffffffff821161021b5760200191813603831361021b57565b6020919283604051948593843782019081520301902090565b9290613768906137769593604086526040860191613674565b926020818503910152613674565b90565b3567ffffffffffffffff8116810361021b5790565b3573ffffffffffffffffffffffffffffffffffffffff8116810361021b5790565b90357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18236030181121561021b57016020813591019167ffffffffffffffff821161021b57813603831361021b57565b9081357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa18336030181121561021b576138da836138f5920160e084526138a961389e61386061384e84806137af565b606060e08a0152610140890191613674565b61386d60208501856137af565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff20898403016101008a0152613674565b9160408101906137af565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff2086840301610120870152613674565b6138e760208501856137af565b908483036020860152613674565b9160408101359061ffff821680920361021b5760c091604084015267ffffffffffffffff61392560608301613418565b16606084015267ffffffffffffffff61394060808301613418565b16608084015260a081013560a084015201359073ffffffffffffffffffffffffffffffffffffffff821680920361021b5760c0015290565b7feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d8698401548060d01c80151590816139e5575b50156139bc5760a01c65ffffffffffff1690565b507feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d86984005460d01c90565b905042115f6139a8565b335f9081527fb7db2dd08fcb62d0c9e08c51941cae53c267786a0b75803fb7960902fc8ef97d602052604090205460ff1615613a2757565b7fe2517d3f000000000000000000000000000000000000000000000000000000005f52336004525f60245260445ffd5b805f527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680060205260405f2073ffffffffffffffffffffffffffffffffffffffff33165f5260205260ff60405f20541615613aae5750565b7fe2517d3f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b60027f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005414613b2c5760027f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b7f3ee5aeb5000000000000000000000000000000000000000000000000000000005f5260045ffd5b805f52600260205260ff60405f205416906005821015610ecd5760018203613b7a575050565b7f0a8c14ec000000000000000000000000000000000000000000000000000000005f52600452602452600160445260645ffd5b905f80808086855af1613bbe613645565b5015613c0857602073ffffffffffffffffffffffffffffffffffffffff7ffbeaa807aad4fcff31eff41f17142e6dcd1babf57c4730e3a4c706ac608cc057926040519586521693a3565b602073ffffffffffffffffffffffffffffffffffffffff7f6b047d8dc1f7b38d6f9a960ffc93bf185e2218056f75b0d410b2e64567f942a1926040519586521693a3565b9065ffffffffffff8091169116019065ffffffffffff8211611b5557565b60ff7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033005416613c9557565b7fd93c0665000000000000000000000000000000000000000000000000000000005f5260045ffd5b73ffffffffffffffffffffffffffffffffffffffff7feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d8698401541661064a5780613d806137769273ffffffffffffffffffffffffffffffffffffffff167fffffffffffffffffffffffff00000000000000000000000000000000000000007feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d86984015416177feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d869840155565b5f6140f1565b613776907f8560dd4a88735ec0892d189314f1b42fca842bd42705b1317b77b4affbe666dd6140f1565b613776907f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a6140f1565b908115613deb575b613776916140f1565b73ffffffffffffffffffffffffffffffffffffffff7feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d8698401541661064a5761377691613eae8273ffffffffffffffffffffffffffffffffffffffff167fffffffffffffffffffffffff00000000000000000000000000000000000000007feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d86984015416177feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d869840155565b9150613de2565b6137769073ffffffffffffffffffffffffffffffffffffffff7feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d8698401541673ffffffffffffffffffffffffffffffffffffffff821614613f14575b5f614203565b7fffffffffffffffffffffffff00000000000000000000000000000000000000007feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d869840154167feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d869840155613f0e565b9061377691801580613ffc575b15614203577fffffffffffffffffffffffff00000000000000000000000000000000000000007feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d869840154167feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d869840155614203565b5073ffffffffffffffffffffffffffffffffffffffff7feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d8698401541673ffffffffffffffffffffffffffffffffffffffff831614613f8c565b65ffffffffffff811161406a5765ffffffffffff1690565b7f6dfcc650000000000000000000000000000000000000000000000000000000005f52603060045260245260445ffd5b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c16156140c957565b7fd7e6bcf8000000000000000000000000000000000000000000000000000000005f5260045ffd5b805f527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680060205260405f2073ffffffffffffffffffffffffffffffffffffffff83165f5260205260ff60405f205416155f146141fd57805f527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680060205260405f2073ffffffffffffffffffffffffffffffffffffffff83165f5260205260405f2060017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082541617905573ffffffffffffffffffffffffffffffffffffffff339216907f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d5f80a4600190565b50505f90565b805f527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680060205260405f2073ffffffffffffffffffffffffffffffffffffffff83165f5260205260ff60405f2054165f146141fd57805f527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680060205260405f2073ffffffffffffffffffffffffffffffffffffffff83165f5260205260405f207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00815416905573ffffffffffffffffffffffffffffffffffffffff339216907ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b5f80a460019056fea2646970667358221220b625d8d169c5ca36ead7065b0ad9753eae37d298cf9af9b72dc4bc92bbcc6da864736f6c634300081a0033" + +// MOCK_UNIVERSAL_CORE_READS_BYTECODE is a minimal IUniversalCore stand-in used by +// the x/ucallback integration tests to create a real read request. +// +// UniversalCallback.requestExternalReadSelf consults UniversalCore for the chain +// height and the read base fee. The mock returns a large height and a ZERO fee — +// zero keeps the request off the VaultPC fee-forwarding path, so a request can be +// created without deploying the vault too. +// +// Source: push-chain-core-contracts src/test-mocks/MockUniversalCoreForReads.sol +// Regenerate with `forge build --contracts src/test-mocks/MockUniversalCoreForReads.sol`. +const MOCK_UNIVERSAL_CORE_READS_BYTECODE = "60806040526004361015610011575f80fd5b5f3560e01c806368c70c9e146100ae5763c2d5c08c1461002f575f80fd5b346100aa5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126100aa5760043567ffffffffffffffff81116100aa5761007e90369060040161010c565b5060243567ffffffffffffffff81116100aa5761009f90369060040161010c565b5060206040515f8152f35b5f80fd5b346100aa5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126100aa5760043567ffffffffffffffff81116100aa576100fd90369060040161010c565b5060206040516305f5e1008152f35b81601f820112156100aa5780359067ffffffffffffffff821161019157604051927fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f81601f8601160116840184811067ffffffffffffffff82111761019157604052828452602083830101116100aa57815f926020809301838601378301015290565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffdfea26469706673582212204a550cac9370471c582ae9201303af25c930f22e10fe8e2899a1f613a6e1d07064736f6c634300081a0033" diff --git a/test/utils/contracts_setup.go b/test/utils/contracts_setup.go index dc588b29..3a2534aa 100644 --- a/test/utils/contracts_setup.go +++ b/test/utils/contracts_setup.go @@ -11,6 +11,7 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/pushchain/push-chain-node/app" uetypes "github.com/pushchain/push-chain-node/x/uexecutor/types" + uregistrytypes "github.com/pushchain/push-chain-node/x/uregistry/types" "github.com/stretchr/testify/require" ) @@ -397,3 +398,23 @@ func setupUniversalGatewayPC( ) return nil } + +// SetupUniversalCallback deploys UniversalCallback's runtime code at its reserved +// system address and returns it. +// +// initialize() is never run — DeployContract writes code directly — so any storage +// the test depends on must be set by the caller. The module-address immutable is +// already baked into the bytecode, so access control works without it. +func SetupUniversalCallback(t *testing.T, app *app.ChainApp, ctx sdk.Context) common.Address { + t.Helper() + addr := common.HexToAddress( + uregistrytypes.SYSTEM_CONTRACTS["UNIVERSAL_CALLBACK"].Address) + return DeployContract(t, app, ctx, addr, UNIVERSAL_CALLBACK_BYTECODE) +} + +// SetupMockUniversalCoreForReads deploys the IUniversalCore stand-in that +// UniversalCallback consults when a read request is created. +func SetupMockUniversalCoreForReads(t *testing.T, app *app.ChainApp, ctx sdk.Context) common.Address { + addr := common.HexToAddress("0x00000000000000000000000000000000000C0BE1") + return DeployContract(t, app, ctx, addr, MOCK_UNIVERSAL_CORE_READS_BYTECODE) +} diff --git a/universalClient/core/client.go b/universalClient/core/client.go index 965e7c20..cf1cdb93 100644 --- a/universalClient/core/client.go +++ b/universalClient/core/client.go @@ -31,7 +31,7 @@ type UniversalClient struct { pushCore *pushcore.Client pushSigner *pushsigner.Signer chains *externalchains.Chains - pushChain *pushwatcher.Client + pushWatcher *pushwatcher.Client tssNode *tss.Node } @@ -70,21 +70,23 @@ func NewUniversalClient(ctx context.Context, cfg *config.Config) (*UniversalClie chainsManager := externalchains.NewChains(pushCore, pushSigner, cfg, log) - // Push chain DB is shared by the push chain client and the TSS node. + // Push chain DB is shared by the push watcher and the TSS node. pushDB, err := openPushDB(cfg) if err != nil { return nil, err } - pushChain, err := pushwatcher.NewClient( + pushWatcher, err := pushwatcher.NewClient( pushDB, cfg.GetChainConfig(cfg.PushChainID), pushCore, cfg.PushChainID, log, + pushSigner, + chainsManager, ) if err != nil { - return nil, fmt.Errorf("failed to create push chain client: %w", err) + return nil, fmt.Errorf("failed to create push watcher: %w", err) } tssNode, err := initTSS(ctx, cfg, pushCore, chainsManager, pushSigner, pushDB, log) @@ -102,7 +104,7 @@ func NewUniversalClient(ctx context.Context, cfg *config.Config) (*UniversalClie pushCore: pushCore, pushSigner: pushSigner, chains: chainsManager, - pushChain: pushChain, + pushWatcher: pushWatcher, tssNode: tssNode, }, nil } @@ -130,8 +132,8 @@ func (uc *UniversalClient) Start() error { return fmt.Errorf("failed to start chains manager: %w", err) } - if err := uc.pushChain.Start(uc.ctx); err != nil { - return fmt.Errorf("failed to start push chain client: %w", err) + if err := uc.pushWatcher.Start(uc.ctx); err != nil { + return fmt.Errorf("failed to start push watcher: %w", err) } if uc.tssNode != nil { @@ -166,9 +168,9 @@ func (uc *UniversalClient) shutdown() { } } - if uc.pushChain != nil { - if err := uc.pushChain.Stop(); err != nil { - uc.log.Error().Err(err).Str("subsystem", "push_chain").Msg("subsystem failed to stop") + if uc.pushWatcher != nil { + if err := uc.pushWatcher.Stop(); err != nil { + uc.log.Error().Err(err).Str("subsystem", "push_watcher").Msg("subsystem failed to stop") } } diff --git a/universalClient/externalchains/chains_test.go b/universalClient/externalchains/chains_test.go index 20ed9d84..9426e0a8 100644 --- a/universalClient/externalchains/chains_test.go +++ b/universalClient/externalchains/chains_test.go @@ -413,6 +413,9 @@ type mockChainClient struct { func (m *mockChainClient) Start(ctx context.Context) error { m.startCalled = true; return nil } func (m *mockChainClient) Stop() error { m.stopCalled = true; return m.stopErr } func (m *mockChainClient) IsHealthy() bool { return true } +func (m *mockChainClient) GetReadRequestHandler() (common.ReadRequestHandler, error) { + return nil, nil +} func (m *mockChainClient) GetTxBuilder() (common.TxBuilder, error) { return nil, nil } diff --git a/universalClient/externalchains/common/chain_store.go b/universalClient/externalchains/common/chain_store.go index b67bd1f8..b711087c 100644 --- a/universalClient/externalchains/common/chain_store.go +++ b/universalClient/externalchains/common/chain_store.go @@ -154,24 +154,6 @@ func (cs *ChainStore) UpdateStatusAndEventData(eventID, oldStatus, newStatus str return res.RowsAffected, nil } -// UpdateVoteTxHash updates the vote_tx_hash field for an event -func (cs *ChainStore) UpdateVoteTxHash(eventID string, voteTxHash string) error { - if cs.database == nil { - return fmt.Errorf("database is nil") - } - - result := cs.database.Client(). - Model(&store.Event{}). - Where("event_id = ?", eventID). - Update("vote_tx_hash", voteTxHash) - - if result.Error != nil { - return fmt.Errorf("failed to update vote_tx_hash: %w", result.Error) - } - - return nil -} - // DeleteTerminalEvents deletes events in terminal states (COMPLETED, REVERTED, EXPIRED) // that were updated before the given time func (cs *ChainStore) DeleteTerminalEvents(updatedBefore any) (int64, error) { diff --git a/universalClient/externalchains/common/chain_store_test.go b/universalClient/externalchains/common/chain_store_test.go index a3b80989..bc413cac 100644 --- a/universalClient/externalchains/common/chain_store_test.go +++ b/universalClient/externalchains/common/chain_store_test.go @@ -56,12 +56,6 @@ func TestChainStoreNilDatabase(t *testing.T) { assert.Contains(t, err.Error(), "database is nil") }) - t.Run("UpdateVoteTxHash returns error for nil database", func(t *testing.T) { - err := store.UpdateVoteTxHash("event-1", "0x123") - require.Error(t, err) - assert.Contains(t, err.Error(), "database is nil") - }) - t.Run("InsertEventIfNotExists returns error for nil database", func(t *testing.T) { inserted, err := store.InsertEventIfNotExists(nil) require.Error(t, err) @@ -222,23 +216,6 @@ func TestChainStore_UpdateStatusAndEventData(t *testing.T) { assert.Equal(t, int64(1), rows) } -func TestChainStore_UpdateVoteTxHash(t *testing.T) { - cs := newTestChainStore(t) - - event := &storemodels.Event{ - EventID: "evt-5", - BlockHeight: 50, - Type: storemodels.EventTypeOutbound, - ConfirmationType: storemodels.ConfirmationStandard, - Status: storemodels.StatusConfirmed, - } - _, err := cs.InsertEventIfNotExists(event) - require.NoError(t, err) - - err = cs.UpdateVoteTxHash("evt-5", "0xvotehash") - require.NoError(t, err) -} - func TestChainStore_GetPendingEventsLimit(t *testing.T) { cs := newTestChainStore(t) diff --git a/universalClient/externalchains/common/event_processor.go b/universalClient/externalchains/common/event_processor.go index 3625d306..280ccf40 100644 --- a/universalClient/externalchains/common/event_processor.go +++ b/universalClient/externalchains/common/event_processor.go @@ -3,54 +3,67 @@ package common import ( "context" "encoding/hex" - "encoding/json" "fmt" - "strconv" "strings" "sync" "time" "github.com/mr-tron/base58" "github.com/pushchain/push-chain-node/universalClient/db" - "github.com/pushchain/push-chain-node/universalClient/pushsigner" "github.com/pushchain/push-chain-node/universalClient/store" uexecutortypes "github.com/pushchain/push-chain-node/x/uexecutor/types" "github.com/rs/zerolog" ) -// EventProcessor processes events from the chain's database and votes on them +const eventProcessBatchSize = 1000 + +// VoteSigner is the subset of pushsigner.Signer used by the event processors. +// Defined here (consumer-side) so tests can provide mock implementations. +type VoteSigner interface { + VoteInbound(ctx context.Context, inbound *uexecutortypes.Inbound) (string, error) + VoteOutbound(ctx context.Context, txID string, utxID string, observation *uexecutortypes.OutboundObservation) (string, error) +} + +// EventHandler processes one CONFIRMED event of a registered type. +// Handlers own the event's status transitions; a returned error is logged and +// the event is retried next tick. +type EventHandler interface { + HandleEvent(ctx context.Context, event *store.Event) error +} + +// EventProcessor drains CONFIRMED events from the chain's database and +// dispatches them to the handler registered for their type. Event types +// without a handler are ignored. type EventProcessor struct { - signer *pushsigner.Signer - chainStore *ChainStore - logger zerolog.Logger - chainID string - inboundEnabled bool - outboundEnabled bool - running bool - stopCh chan struct{} - wg sync.WaitGroup + chainStore *ChainStore + handlers map[string]EventHandler + chainID string + logger zerolog.Logger + running bool + stopCh chan struct{} + wg sync.WaitGroup } -// NewEventProcessor creates a new event processor +// NewEventProcessor creates a new event processor. Register handlers before Start. func NewEventProcessor( - signer *pushsigner.Signer, database *db.DB, chainID string, - inboundEnabled bool, - outboundEnabled bool, logger zerolog.Logger, ) *EventProcessor { return &EventProcessor{ - signer: signer, - chainStore: NewChainStore(database), - chainID: chainID, - inboundEnabled: inboundEnabled, - outboundEnabled: outboundEnabled, - logger: logger.With().Str("component", "event_processor").Str("chain", chainID).Logger(), - stopCh: make(chan struct{}), + chainStore: NewChainStore(database), + handlers: make(map[string]EventHandler), + chainID: chainID, + logger: logger.With().Str("component", "event_processor").Str("chain", chainID).Logger(), + stopCh: make(chan struct{}), } } +// RegisterHandler registers a handler for an event type. Must be called before Start. +func (ep *EventProcessor) RegisterHandler(eventType string, handler EventHandler) { + ep.handlers[eventType] = handler +} + // Start begins processing events func (ep *EventProcessor) Start(ctx context.Context) error { if ep.running { @@ -103,7 +116,6 @@ func (ep *EventProcessor) processLoop(ctx context.Context) { ep.logger.Debug().Msg("stop signal received, stopping event processor") return case <-ticker.C: - // Fetch 1000 CONFIRMED events and process them if err := ep.processConfirmedEvents(ctx); err != nil { ep.logger.Error().Err(err).Msg("failed to process confirmed events") } @@ -111,123 +123,43 @@ func (ep *EventProcessor) processLoop(ctx context.Context) { } } -// processConfirmedEvents processes confirmed events (both inbound and outbound) +// processConfirmedEvents dispatches CONFIRMED events to their registered handlers. func (ep *EventProcessor) processConfirmedEvents(ctx context.Context) error { - events, err := ep.chainStore.GetConfirmedEvents(1000) + events, err := ep.chainStore.GetConfirmedEvents(eventProcessBatchSize) if err != nil { return fmt.Errorf("failed to get confirmed events: %w", err) } for _, event := range events { - if event.Type == store.EventTypeInbound { - if !ep.inboundEnabled { - ep.logger.Warn().Str("event_id", event.EventID).Msg("inbound disabled, skipping inbound event processing") - continue - } - if err := ep.processInboundEvent(ctx, &event); err != nil { - ep.logger.Error(). - Err(err). - Str("event_id", event.EventID). - Msg("failed to vote on inbound event") - continue - } - } else if event.Type == store.EventTypeOutbound { - if !ep.outboundEnabled { - ep.logger.Warn().Str("event_id", event.EventID).Msg("outbound disabled, skipping outbound event processing") - continue - } - if err := ep.processOutboundEvent(ctx, &event); err != nil { - ep.logger.Error(). - Err(err). - Str("event_id", event.EventID). - Msg("failed to vote on outbound event") - continue - } + handler, ok := ep.handlers[event.Type] + if !ok { + continue } - } - - return nil -} - -// processOutboundEvent processes an outbound event by voting on it -func (ep *EventProcessor) processOutboundEvent(ctx context.Context, event *store.Event) error { - ep.logger.Debug(). - Str("event_id", event.EventID). - Msg("processing outbound event") - - // Parse outbound event data once - outboundData, err := ep.parseOutboundEventData(event) - if err != nil { - return fmt.Errorf("failed to parse outbound event data: %w", err) - } - - txID := outboundData.TxID - utxID := outboundData.UniversalTxID - - // Build observation from parsed data - observation, err := ep.buildOutboundObservation(event, outboundData) - if err != nil { - return fmt.Errorf("failed to build outbound observation: %w", err) - } - - // Vote on outbound - voteTxHash, err := ep.signer.VoteOutbound(ctx, txID, utxID, observation) - if err != nil { - return fmt.Errorf("failed to vote on outbound: %w", err) - } - // Atomically record vote hash and flip status in one DB write - rowsAffected, err := ep.chainStore.UpdateStatusAndVoteTxHash(event.EventID, store.StatusConfirmed, store.StatusCompleted, voteTxHash) - if err != nil { - return fmt.Errorf("failed to update event status and vote_tx_hash: %w", err) - } - - if rowsAffected == 0 { - return nil // already completed by another validator + if err := handler.HandleEvent(ctx, &event); err != nil { + ep.logger.Error(). + Err(err). + Str("event_id", event.EventID). + Str("type", event.Type). + Msg("failed to process event") + } } - ep.logger.Info(). - Str("event_id", event.EventID). - Str("type", event.Type). - Str("vote_tx_hash", voteTxHash). - Msg("event marked as COMPLETED") - return nil } -// processInboundEvent processes an inbound event by voting on it and confirming it -func (ep *EventProcessor) processInboundEvent(ctx context.Context, event *store.Event) error { - ep.logger.Debug(). - Str("event_id", event.EventID). - Msg("processing inbound event") - - // Extract inbound data from event - inbound, err := ep.constructInbound(event) - if err != nil { - return fmt.Errorf("failed to construct inbound: %w", err) - } - - // Execute vote on blockchain - voteTxHash, err := ep.signer.VoteInbound(ctx, inbound) - if err != nil { - ep.logger.Error(). - Str("event_id", event.EventID). - Err(err). - Msg("failed to vote on event - keeping status for retry") - return err - } - - // Atomically record vote hash and flip status in one DB write - rowsAffected, err := ep.chainStore.UpdateStatusAndVoteTxHash(event.EventID, store.StatusConfirmed, store.StatusCompleted, voteTxHash) +// markEventCompleted atomically records the vote hash and flips CONFIRMED -> COMPLETED. +func markEventCompleted(chainStore *ChainStore, logger zerolog.Logger, event *store.Event, voteTxHash string) error { + rowsAffected, err := chainStore.UpdateStatusAndVoteTxHash(event.EventID, store.StatusConfirmed, store.StatusCompleted, voteTxHash) if err != nil { return fmt.Errorf("failed to update event status after successful vote: %w", err) } if rowsAffected == 0 { - return nil // already completed by another validator + return nil // already completed } - ep.logger.Info(). + logger.Info(). Str("event_id", event.EventID). Str("type", event.Type). Str("vote_tx_hash", voteTxHash). @@ -236,86 +168,25 @@ func (ep *EventProcessor) processInboundEvent(ctx context.Context, event *store. return nil } -// constructInbound creates an Inbound message from event data -func (ep *EventProcessor) constructInbound(event *store.Event) (*uexecutortypes.Inbound, error) { - var eventData UniversalTx - - if event == nil { - return nil, fmt.Errorf("event is nil") - } - - if event.EventData == nil { - return nil, fmt.Errorf("event data is missing for event_id: %s", event.EventID) - } - - if err := json.Unmarshal(event.EventData, &eventData); err != nil { - return nil, fmt.Errorf("failed to unmarshal event data: %w", err) - } - - // Map txType from eventData to proper enum value - txType := uexecutortypes.TxType_UNSPECIFIED_TX - switch eventData.TxType { - case 0: - txType = uexecutortypes.TxType_GAS - case 1: - txType = uexecutortypes.TxType_GAS_AND_PAYLOAD - case 2: - txType = uexecutortypes.TxType_FUNDS - case 3: - txType = uexecutortypes.TxType_FUNDS_AND_PAYLOAD - default: - txType = uexecutortypes.TxType_UNSPECIFIED_TX - } - - // Extract txHash from EventID (format: "txHash:logIndex") +// eventTxHash extracts the tx hash from an EventID (format: "txHash:logIndex" +// or "signature:logIndex"), converting base58 signatures to 0x-prefixed hex. +// Falls back to the raw value if conversion fails. +func eventTxHash(eventID string) string { txHash := "" - parts := strings.Split(event.EventID, ":") + parts := strings.Split(eventID, ":") if len(parts) > 0 { txHash = parts[0] } - // Convert txHash to hex format if it's in base58 - txHashHex, err := ep.base58ToHex(txHash) + txHashHex, err := base58ToHex(txHash) if err != nil { - ep.logger.Warn(). - Str("tx_hash", txHash). - Err(err). - Msg("failed to convert txHash to hex, using original value") - txHashHex = txHash - } - - inboundMsg := &uexecutortypes.Inbound{ - SourceChain: eventData.SourceChain, - TxHash: txHashHex, - Sender: eventData.Sender, - Recipient: eventData.Recipient, - Amount: eventData.Amount, - AssetAddr: eventData.Token, - LogIndex: strconv.FormatUint(uint64(eventData.LogIndex), 10), - TxType: txType, - IsCEA: eventData.FromCEA, - RawPayload: eventData.RawPayload, - } - - // Set revert instructions if revert fund recipient is present - if eventData.RevertFundRecipient != "" { - inboundMsg.RevertInstructions = &uexecutortypes.RevertInstructions{ - FundRecipient: eventData.RevertFundRecipient, - } - } - - // Use event's VerificationData if present, otherwise fall back to txHash - if eventData.VerificationData == "" || eventData.VerificationData == "0x" { - inboundMsg.VerificationData = txHashHex - } else { - inboundMsg.VerificationData = eventData.VerificationData + return txHash } - - return inboundMsg, nil + return txHashHex } // base58ToHex converts a base58 encoded string to hex format (0x...) -func (ep *EventProcessor) base58ToHex(base58Str string) (string, error) { +func base58ToHex(base58Str string) (string, error) { if base58Str == "" { return "0x", nil } @@ -334,65 +205,3 @@ func (ep *EventProcessor) base58ToHex(base58Str string) (string, error) { // Convert to hex with 0x prefix return "0x" + hex.EncodeToString(decoded), nil } - -// parseOutboundEventData unmarshals event data into an OutboundEvent struct -func (ep *EventProcessor) parseOutboundEventData(event *store.Event) (*OutboundEvent, error) { - if event == nil { - return nil, fmt.Errorf("event is nil") - } - - if len(event.EventData) == 0 { - return nil, fmt.Errorf("event data is empty") - } - - var eventData OutboundEvent - if err := json.Unmarshal(event.EventData, &eventData); err != nil { - return nil, fmt.Errorf("failed to unmarshal event data: %w", err) - } - - if eventData.TxID == "" { - return nil, fmt.Errorf("tx_id not found in event data") - } - - if eventData.UniversalTxID == "" { - return nil, fmt.Errorf("universal_tx_id not found in event data") - } - - return &eventData, nil -} - -// buildOutboundObservation builds an OutboundObservation from event metadata and parsed outbound data -func (ep *EventProcessor) buildOutboundObservation(event *store.Event, outboundData *OutboundEvent) (*uexecutortypes.OutboundObservation, error) { - // Extract txHash from EventID (format: "txHash:logIndex" or "signature:logIndex") - txHash := "" - parts := strings.Split(event.EventID, ":") - if len(parts) > 0 { - txHash = parts[0] - } - - // Convert txHash to hex format if it's in base58 - txHashHex, err := ep.base58ToHex(txHash) - if err != nil { - ep.logger.Warn(). - Str("tx_hash", txHash). - Err(err). - Msg("failed to convert txHash to hex, using original value") - txHashHex = txHash - } - - gasFeeUsed := "0" - if outboundData.GasFeeUsed != "" { - gasFeeUsed = outboundData.GasFeeUsed - } - - observation := &uexecutortypes.OutboundObservation{ - Success: true, - BlockHeight: event.BlockHeight, - TxHash: txHashHex, - ErrorMsg: "", - GasFeeUsed: gasFeeUsed, - Pc20WrapperAddress: outboundData.Pc20WrapperAddress, - } - - return observation, nil -} diff --git a/universalClient/externalchains/common/event_processor_test.go b/universalClient/externalchains/common/event_processor_test.go index 4a08c305..df8a1f12 100644 --- a/universalClient/externalchains/common/event_processor_test.go +++ b/universalClient/externalchains/common/event_processor_test.go @@ -2,7 +2,8 @@ package common import ( "context" - "encoding/json" + "fmt" + "math/big" "testing" "time" @@ -15,1042 +16,256 @@ import ( uexecutortypes "github.com/pushchain/push-chain-node/x/uexecutor/types" ) -func TestNewEventProcessor(t *testing.T) { - t.Run("creates event processor with valid params", func(t *testing.T) { - logger := zerolog.Nop() - chainID := "eip155:1" - - processor := NewEventProcessor(nil, nil, chainID, true, true, logger) - - require.NotNil(t, processor) - assert.Equal(t, chainID, processor.chainID) - assert.False(t, processor.running) - assert.NotNil(t, processor.stopCh) - assert.NotNil(t, processor.chainStore) - }) -} - -func TestEventProcessorIsRunning(t *testing.T) { - t.Run("returns false when not running", func(t *testing.T) { - processor := &EventProcessor{running: false} - assert.False(t, processor.IsRunning()) - }) - - t.Run("returns true when running", func(t *testing.T) { - processor := &EventProcessor{running: true} - assert.True(t, processor.IsRunning()) - }) +type fakeVoteSigner struct { + inboundVotes int + outboundVotes int + txHash string + err error } -func TestEventProcessorStop(t *testing.T) { - t.Run("stop when not running returns nil", func(t *testing.T) { - processor := &EventProcessor{running: false} - err := processor.Stop() - assert.NoError(t, err) - }) +func (f *fakeVoteSigner) VoteInbound(ctx context.Context, inbound *uexecutortypes.Inbound) (string, error) { + if f.err != nil { + return "", f.err + } + f.inboundVotes++ + return f.txHash, nil } -func TestEventProcessorBase58ToHex(t *testing.T) { - logger := zerolog.Nop() - processor := NewEventProcessor(nil, nil, "test-chain", true, true, logger) - - t.Run("empty string returns 0x", func(t *testing.T) { - result, err := processor.base58ToHex("") - require.NoError(t, err) - assert.Equal(t, "0x", result) - }) - - t.Run("already hex returns as is", func(t *testing.T) { - input := "0xabcdef1234567890" - result, err := processor.base58ToHex(input) - require.NoError(t, err) - assert.Equal(t, input, result) - }) - - t.Run("valid base58 converts to hex", func(t *testing.T) { - // "3yZe7d" is base58 for bytes [1, 2, 3, 4] - input := "2VfUX" - result, err := processor.base58ToHex(input) - require.NoError(t, err) - assert.True(t, len(result) > 2) - assert.Equal(t, "0x", result[:2]) - }) - - t.Run("invalid base58 returns error", func(t *testing.T) { - // Base58 doesn't include 0, O, I, l - input := "0OIl" - _, err := processor.base58ToHex(input) - require.Error(t, err) - }) +func (f *fakeVoteSigner) VoteOutbound(ctx context.Context, txID string, utxID string, observation *uexecutortypes.OutboundObservation) (string, error) { + if f.err != nil { + return "", f.err + } + f.outboundVotes++ + return f.txHash, nil } -func TestEventProcessorConstructInbound(t *testing.T) { - logger := zerolog.Nop() - processor := NewEventProcessor(nil, nil, "eip155:1", true, true, logger) - - t.Run("nil event returns error", func(t *testing.T) { - inbound, err := processor.constructInbound(nil) - require.Error(t, err) - assert.Nil(t, inbound) - assert.Contains(t, err.Error(), "event is nil") - }) - - t.Run("nil event data returns error", func(t *testing.T) { - event := &store.Event{ - EventID: "0x123:0", - EventData: nil, - } - inbound, err := processor.constructInbound(event) - require.Error(t, err) - assert.Nil(t, inbound) - assert.Contains(t, err.Error(), "event data is missing") - }) - - t.Run("invalid JSON returns error", func(t *testing.T) { - event := &store.Event{ - EventID: "0x123:0", - EventData: []byte("invalid json"), - } - inbound, err := processor.constructInbound(event) - require.Error(t, err) - assert.Nil(t, inbound) - }) - - t.Run("valid event data constructs inbound", func(t *testing.T) { - eventData := UniversalTx{ - SourceChain: "eip155:1", - LogIndex: 5, - Sender: "0xsender123", - Recipient: "push1recipient", - Token: "0xtoken", - Amount: "1000000", - TxType: 2, // FUNDS - } - eventDataBytes, _ := json.Marshal(eventData) - - event := &store.Event{ - EventID: "0xabc123:5", - EventData: eventDataBytes, - } - - inbound, err := processor.constructInbound(event) - require.NoError(t, err) - require.NotNil(t, inbound) - assert.Equal(t, "eip155:1", inbound.SourceChain) - assert.Equal(t, "0xsender123", inbound.Sender) - assert.Equal(t, "1000000", inbound.Amount) - assert.Equal(t, uexecutortypes.TxType_FUNDS, inbound.TxType) - }) - - t.Run("passes all fields unconditionally to inbound", func(t *testing.T) { - eventData := UniversalTx{ - SourceChain: "eip155:1", - LogIndex: 3, - Sender: "0xsender", - Recipient: "0xrecipient", - Token: "0xtoken", - Amount: "500", - RawPayload: "0xdeadbeef", - VerificationData: "0xsigdata", - RevertFundRecipient: "0xrevert", - TxType: 3, // FUNDS_AND_PAYLOAD - FromCEA: true, - } - eventDataBytes, _ := json.Marshal(eventData) - - event := &store.Event{ - EventID: "0xtxhash:3", - EventData: eventDataBytes, - } - - inbound, err := processor.constructInbound(event) - require.NoError(t, err) - require.NotNil(t, inbound) - assert.Equal(t, "0xrecipient", inbound.Recipient) - assert.Equal(t, "0xdeadbeef", inbound.RawPayload) - assert.Equal(t, "0xsigdata", inbound.VerificationData) - assert.True(t, inbound.IsCEA) - require.NotNil(t, inbound.RevertInstructions) - assert.Equal(t, "0xrevert", inbound.RevertInstructions.FundRecipient) - }) - - t.Run("passes raw payload and verification data for non-payload tx types", func(t *testing.T) { - // Core will strip these — UV just passes everything through - eventData := UniversalTx{ - SourceChain: "eip155:1", - Sender: "0xsender", - Recipient: "0xrecipient", - Amount: "1000", - RawPayload: "0xcafe", - VerificationData: "0xsig", - TxType: 2, // FUNDS (non-payload type) - } - eventDataBytes, _ := json.Marshal(eventData) - - event := &store.Event{ - EventID: "0xhash:0", - EventData: eventDataBytes, - } - - inbound, err := processor.constructInbound(event) - require.NoError(t, err) - assert.Equal(t, "0xrecipient", inbound.Recipient) - assert.Equal(t, "0xcafe", inbound.RawPayload) - assert.Equal(t, "0xsig", inbound.VerificationData) - }) - - t.Run("no revert instructions when revert recipient is empty", func(t *testing.T) { - eventData := UniversalTx{ - SourceChain: "eip155:1", - Sender: "0xsender", - Amount: "100", - TxType: 0, // GAS - RevertFundRecipient: "", - } - eventDataBytes, _ := json.Marshal(eventData) - - event := &store.Event{ - EventID: "0xhash:0", - EventData: eventDataBytes, - } - - inbound, err := processor.constructInbound(event) - require.NoError(t, err) - assert.Nil(t, inbound.RevertInstructions) - }) - - t.Run("tx type mapping", func(t *testing.T) { - testCases := []struct { - txType uint - expected uexecutortypes.TxType - }{ - {0, uexecutortypes.TxType_GAS}, - {1, uexecutortypes.TxType_GAS_AND_PAYLOAD}, - {2, uexecutortypes.TxType_FUNDS}, - {3, uexecutortypes.TxType_FUNDS_AND_PAYLOAD}, - {99, uexecutortypes.TxType_UNSPECIFIED_TX}, // Unknown defaults to unspecified - } - - for _, tc := range testCases { - eventData := UniversalTx{ - SourceChain: "eip155:1", - TxType: tc.txType, - } - eventDataBytes, _ := json.Marshal(eventData) - - event := &store.Event{ - EventID: "0xabc:0", - EventData: eventDataBytes, - } - - inbound, err := processor.constructInbound(event) - require.NoError(t, err) - assert.Equal(t, tc.expected, inbound.TxType, "TxType %d should map to %v", tc.txType, tc.expected) - } - }) +type fakeEventHandler struct { + handled []string + err error } -func TestEventProcessorParseOutboundEventData(t *testing.T) { - logger := zerolog.Nop() - processor := NewEventProcessor(nil, nil, "eip155:1", true, true, logger) - - t.Run("nil event returns error", func(t *testing.T) { - data, err := processor.parseOutboundEventData(nil) - require.Error(t, err) - assert.Nil(t, data) - assert.Contains(t, err.Error(), "event is nil") - }) - - t.Run("empty event data returns error", func(t *testing.T) { - event := &store.Event{ - EventID: "test", - EventData: []byte{}, - } - data, err := processor.parseOutboundEventData(event) - require.Error(t, err) - assert.Nil(t, data) - assert.Contains(t, err.Error(), "event data is empty") - }) - - t.Run("valid outbound event extracts IDs and gas fee", func(t *testing.T) { - eventData := OutboundEvent{ - TxID: "0x1234", - UniversalTxID: "0xabcd", - GasFeeUsed: "42000000000000", - } - eventDataBytes, _ := json.Marshal(eventData) - - event := &store.Event{ - EventID: "test", - EventData: eventDataBytes, - } - - data, err := processor.parseOutboundEventData(event) - require.NoError(t, err) - assert.Equal(t, "0x1234", data.TxID) - assert.Equal(t, "0xabcd", data.UniversalTxID) - assert.Equal(t, "42000000000000", data.GasFeeUsed) - }) - - t.Run("missing tx_id returns error", func(t *testing.T) { - eventData := OutboundEvent{ - TxID: "", - UniversalTxID: "0xabcd", - } - eventDataBytes, _ := json.Marshal(eventData) - - event := &store.Event{ - EventID: "test", - EventData: eventDataBytes, - } - - data, err := processor.parseOutboundEventData(event) - require.Error(t, err) - assert.Nil(t, data) - assert.Contains(t, err.Error(), "tx_id not found") - }) - - t.Run("missing universal_tx_id returns error", func(t *testing.T) { - eventData := OutboundEvent{ - TxID: "0x1234", - UniversalTxID: "", - } - eventDataBytes, _ := json.Marshal(eventData) - - event := &store.Event{ - EventID: "test", - EventData: eventDataBytes, - } - - data, err := processor.parseOutboundEventData(event) - require.Error(t, err) - assert.Nil(t, data) - assert.Contains(t, err.Error(), "universal_tx_id not found") - }) +func (f *fakeEventHandler) HandleEvent(ctx context.Context, event *store.Event) error { + f.handled = append(f.handled, event.EventID) + return f.err } -func TestEventProcessorBuildOutboundObservation(t *testing.T) { - logger := zerolog.Nop() - processor := NewEventProcessor(nil, nil, "eip155:1", true, true, logger) - - t.Run("builds observation with gas fee from parsed data", func(t *testing.T) { - outboundData := &OutboundEvent{ - TxID: "0x1234", - UniversalTxID: "0xabcd", - GasFeeUsed: "42000000000000", - } - - event := &store.Event{ - EventID: "0xabc123:5", - BlockHeight: 12345, - } - - obs, err := processor.buildOutboundObservation(event, outboundData) - require.NoError(t, err) - require.NotNil(t, obs) - assert.True(t, obs.Success) - assert.Equal(t, uint64(12345), obs.BlockHeight) - assert.Equal(t, "0xabc123", obs.TxHash) - assert.Equal(t, "42000000000000", obs.GasFeeUsed) - }) - - t.Run("missing gas fee defaults to 0", func(t *testing.T) { - outboundData := &OutboundEvent{ - TxID: "0x1234", - UniversalTxID: "0xabcd", - } - - event := &store.Event{ - EventID: "0xabc123:5", - BlockHeight: 12345, - } - - obs, err := processor.buildOutboundObservation(event, outboundData) - require.NoError(t, err) - require.NotNil(t, obs) - assert.Equal(t, "0", obs.GasFeeUsed) - }) - - t.Run("handles base58 tx hash", func(t *testing.T) { - outboundData := &OutboundEvent{ - TxID: "0x1234", - UniversalTxID: "0xabcd", - } - - event := &store.Event{ - EventID: "2VfUX:0", // Base58 encoded - BlockHeight: 100, - } - - obs, err := processor.buildOutboundObservation(event, outboundData) - require.NoError(t, err) - require.NotNil(t, obs) - assert.True(t, len(obs.TxHash) >= 2) - }) +func newTestDB(t *testing.T) *ucdb.DB { + t.Helper() + database, err := ucdb.OpenInMemoryDB(true) + require.NoError(t, err) + t.Cleanup(func() { _ = database.Close() }) + return database } -func TestProcessOutboundEvent(t *testing.T) { - logger := zerolog.Nop() - ctx := context.Background() - - setupDB := func(t *testing.T) *ucdb.DB { - t.Helper() - database, err := ucdb.OpenInMemoryDB(true) - require.NoError(t, err) - return database - } - - t.Run("nil event data returns parse error", func(t *testing.T) { - database := setupDB(t) - defer database.Close() - ep := NewEventProcessor(nil, database, "eip155:1", true, true, logger) - - event := &store.Event{ - EventID: "0xabc:0", - EventData: nil, - } - err := ep.processOutboundEvent(ctx, event) - require.Error(t, err) - assert.Contains(t, err.Error(), "failed to parse outbound event data") - }) - - t.Run("empty event data returns parse error", func(t *testing.T) { - database := setupDB(t) - defer database.Close() - ep := NewEventProcessor(nil, database, "eip155:1", true, true, logger) - - event := &store.Event{ - EventID: "0xabc:0", - EventData: []byte{}, - } - err := ep.processOutboundEvent(ctx, event) - require.Error(t, err) - assert.Contains(t, err.Error(), "failed to parse outbound event data") - }) - - t.Run("invalid JSON event data returns parse error", func(t *testing.T) { - database := setupDB(t) - defer database.Close() - ep := NewEventProcessor(nil, database, "eip155:1", true, true, logger) - - event := &store.Event{ - EventID: "0xabc:0", - EventData: []byte("not json"), - } - err := ep.processOutboundEvent(ctx, event) - require.Error(t, err) - assert.Contains(t, err.Error(), "failed to parse outbound event data") - }) - - t.Run("missing tx_id returns parse error", func(t *testing.T) { - database := setupDB(t) - defer database.Close() - ep := NewEventProcessor(nil, database, "eip155:1", true, true, logger) - - eventData, _ := json.Marshal(OutboundEvent{ - TxID: "", - UniversalTxID: "0xutxid", - }) - event := &store.Event{ - EventID: "0xabc:0", - EventData: eventData, - } - err := ep.processOutboundEvent(ctx, event) - require.Error(t, err) - assert.Contains(t, err.Error(), "failed to parse outbound event data") - }) - - t.Run("missing universal_tx_id returns parse error", func(t *testing.T) { - database := setupDB(t) - defer database.Close() - ep := NewEventProcessor(nil, database, "eip155:1", true, true, logger) - - eventData, _ := json.Marshal(OutboundEvent{ - TxID: "0xtxid", - UniversalTxID: "", - }) - event := &store.Event{ - EventID: "0xabc:0", - EventData: eventData, - } - err := ep.processOutboundEvent(ctx, event) - require.Error(t, err) - assert.Contains(t, err.Error(), "failed to parse outbound event data") +func seedConfirmedEvent(t *testing.T, database *ucdb.DB, eventID, eventType string, eventData []byte) { + t.Helper() + result := database.Client().Create(&store.Event{ + EventID: eventID, + Type: eventType, + ConfirmationType: store.ConfirmationInstant, + Status: store.StatusConfirmed, + EventData: eventData, }) + require.NoError(t, result.Error) } -func TestProcessInboundEvent(t *testing.T) { - logger := zerolog.Nop() - ctx := context.Background() - - setupDB := func(t *testing.T) *ucdb.DB { - t.Helper() - database, err := ucdb.OpenInMemoryDB(true) - require.NoError(t, err) - return database - } - - t.Run("nil event data returns construct error", func(t *testing.T) { - database := setupDB(t) - defer database.Close() - ep := NewEventProcessor(nil, database, "eip155:1", true, true, logger) - - event := &store.Event{ - EventID: "0xabc:0", - EventData: nil, - } - err := ep.processInboundEvent(ctx, event) - require.Error(t, err) - assert.Contains(t, err.Error(), "failed to construct inbound") - }) - - t.Run("invalid JSON event data returns construct error", func(t *testing.T) { - database := setupDB(t) - defer database.Close() - ep := NewEventProcessor(nil, database, "eip155:1", true, true, logger) - - event := &store.Event{ - EventID: "0xabc:0", - EventData: []byte("{not valid json}"), - } - err := ep.processInboundEvent(ctx, event) - require.Error(t, err) - assert.Contains(t, err.Error(), "failed to construct inbound") - }) +func TestNewEventProcessor(t *testing.T) { + processor := NewEventProcessor(nil, "eip155:1", zerolog.Nop()) + + require.NotNil(t, processor) + assert.Equal(t, "eip155:1", processor.chainID) + assert.False(t, processor.running) + assert.NotNil(t, processor.stopCh) + assert.NotNil(t, processor.chainStore) + assert.Empty(t, processor.handlers) } -func TestProcessConfirmedEventsRouting(t *testing.T) { - logger := zerolog.Nop() - ctx := context.Background() - - setupDB := func(t *testing.T, events []store.Event) *ucdb.DB { - t.Helper() - database, err := ucdb.OpenInMemoryDB(true) - require.NoError(t, err) - for _, e := range events { - result := database.Client().Create(&e) - require.NoError(t, result.Error) - } - return database - } - - t.Run("no confirmed events returns nil", func(t *testing.T) { - database := setupDB(t, nil) - defer database.Close() - ep := NewEventProcessor(nil, database, "eip155:1", true, true, logger) +func TestEventProcessor_DispatchesByType(t *testing.T) { + database := newTestDB(t) + ep := NewEventProcessor(database, "eip155:1", zerolog.Nop()) - err := ep.processConfirmedEvents(ctx) - require.NoError(t, err) - }) - - t.Run("only pending events are ignored", func(t *testing.T) { - database := setupDB(t, []store.Event{ - { - EventID: "0xpending:0", - Status: store.StatusPending, - Type: store.EventTypeInbound, - EventData: []byte("{}"), - }, - }) - defer database.Close() - ep := NewEventProcessor(nil, database, "eip155:1", true, true, logger) - - err := ep.processConfirmedEvents(ctx) - require.NoError(t, err) - - // Event should remain PENDING (not picked up) - var evt store.Event - database.Client().Where("event_id = ?", "0xpending:0").First(&evt) - assert.Equal(t, store.StatusPending, evt.Status) - }) - - t.Run("inbound with bad data fails gracefully and continues to next event", func(t *testing.T) { - database := setupDB(t, []store.Event{ - { - EventID: "0xbad_inbound:0", - Status: store.StatusConfirmed, - Type: store.EventTypeInbound, - EventData: []byte("not json"), - }, - { - EventID: "0xbad_inbound2:0", - Status: store.StatusConfirmed, - Type: store.EventTypeInbound, - EventData: nil, - }, - }) - defer database.Close() - ep := NewEventProcessor(nil, database, "eip155:1", true, true, logger) - - // Should not return error - errors on individual events are logged and skipped - err := ep.processConfirmedEvents(ctx) - require.NoError(t, err) - - // Both events should remain CONFIRMED (failed to process, not updated) - var evt1, evt2 store.Event - database.Client().Where("event_id = ?", "0xbad_inbound:0").First(&evt1) - assert.Equal(t, store.StatusConfirmed, evt1.Status) - database.Client().Where("event_id = ?", "0xbad_inbound2:0").First(&evt2) - assert.Equal(t, store.StatusConfirmed, evt2.Status) - }) - - t.Run("outbound with bad data fails gracefully and continues to next event", func(t *testing.T) { - database := setupDB(t, []store.Event{ - { - EventID: "0xbad_outbound:0", - Status: store.StatusConfirmed, - Type: store.EventTypeOutbound, - EventData: []byte("not json"), - }, - { - EventID: "0xbad_outbound2:0", - Status: store.StatusConfirmed, - Type: store.EventTypeOutbound, - EventData: []byte{}, - }, - }) - defer database.Close() - ep := NewEventProcessor(nil, database, "eip155:1", true, true, logger) - - err := ep.processConfirmedEvents(ctx) - require.NoError(t, err) - - // Both events should remain CONFIRMED - var evt1, evt2 store.Event - database.Client().Where("event_id = ?", "0xbad_outbound:0").First(&evt1) - assert.Equal(t, store.StatusConfirmed, evt1.Status) - database.Client().Where("event_id = ?", "0xbad_outbound2:0").First(&evt2) - assert.Equal(t, store.StatusConfirmed, evt2.Status) - }) - - t.Run("mixed inbound and outbound with bad data both fail gracefully", func(t *testing.T) { - database := setupDB(t, []store.Event{ - { - EventID: "0xin:0", - Status: store.StatusConfirmed, - Type: store.EventTypeInbound, - EventData: []byte("bad"), - }, - { - EventID: "0xout:0", - Status: store.StatusConfirmed, - Type: store.EventTypeOutbound, - EventData: []byte("bad"), - }, - }) - defer database.Close() - ep := NewEventProcessor(nil, database, "eip155:1", true, true, logger) + inboundHandler := &fakeEventHandler{} + ep.RegisterHandler(store.EventTypeInbound, inboundHandler) - err := ep.processConfirmedEvents(ctx) - require.NoError(t, err) - - var inEvt, outEvt store.Event - database.Client().Where("event_id = ?", "0xin:0").First(&inEvt) - assert.Equal(t, store.StatusConfirmed, inEvt.Status) - database.Client().Where("event_id = ?", "0xout:0").First(&outEvt) - assert.Equal(t, store.StatusConfirmed, outEvt.Status) - }) - - t.Run("outbound missing tx_id in valid JSON stays CONFIRMED", func(t *testing.T) { - eventData, _ := json.Marshal(OutboundEvent{ - TxID: "", - UniversalTxID: "0xutxid", - }) - database := setupDB(t, []store.Event{ - { - EventID: "0xno_txid:0", - Status: store.StatusConfirmed, - Type: store.EventTypeOutbound, - EventData: eventData, - }, - }) - defer database.Close() - ep := NewEventProcessor(nil, database, "eip155:1", true, true, logger) - - err := ep.processConfirmedEvents(ctx) - require.NoError(t, err) - - var evt store.Event - database.Client().Where("event_id = ?", "0xno_txid:0").First(&evt) - assert.Equal(t, store.StatusConfirmed, evt.Status) - }) - - t.Run("unknown event type is silently skipped", func(t *testing.T) { - database := setupDB(t, []store.Event{ - { - EventID: "0xunknown:0", - Status: store.StatusConfirmed, - Type: "UNKNOWN_TYPE", - EventData: []byte("{}"), - }, - }) - defer database.Close() - ep := NewEventProcessor(nil, database, "eip155:1", true, true, logger) + seedConfirmedEvent(t, database, "0xin:0", store.EventTypeInbound, []byte("{}")) + seedConfirmedEvent(t, database, "0xout:0", store.EventTypeOutbound, []byte("{}")) // no handler registered - err := ep.processConfirmedEvents(ctx) - require.NoError(t, err) + require.NoError(t, ep.processConfirmedEvents(context.Background())) - // Event should remain CONFIRMED (no handler for this type) - var evt store.Event - database.Client().Where("event_id = ?", "0xunknown:0").First(&evt) - assert.Equal(t, store.StatusConfirmed, evt.Status) - }) + assert.Equal(t, []string{"0xin:0"}, inboundHandler.handled) } -func TestProcessLoopContextCancellation(t *testing.T) { - logger := zerolog.Nop() - database, err := ucdb.OpenInMemoryDB(true) - require.NoError(t, err) - defer database.Close() - - ep := NewEventProcessor(nil, database, "eip155:1", true, true, logger) - - t.Run("processLoop exits promptly on context cancel", func(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) - - err := ep.Start(ctx) - require.NoError(t, err) - assert.True(t, ep.IsRunning()) - - // Cancel context and wait for stop - cancel() +func TestEventProcessor_HandlerErrorKeepsProcessing(t *testing.T) { + database := newTestDB(t) + ep := NewEventProcessor(database, "eip155:1", zerolog.Nop()) - // The wg.Wait inside Stop() will block until processLoop exits - done := make(chan struct{}) - go func() { - ep.Stop() - close(done) - }() + failing := &fakeEventHandler{err: fmt.Errorf("boom")} + ep.RegisterHandler(store.EventTypeInbound, failing) - select { - case <-done: - // processLoop exited within reasonable time - case <-time.After(10 * time.Second): - t.Fatal("processLoop did not exit within 10 seconds after context cancellation") - } + seedConfirmedEvent(t, database, "0xin:0", store.EventTypeInbound, []byte("{}")) + seedConfirmedEvent(t, database, "0xin:1", store.EventTypeInbound, []byte("{}")) - assert.False(t, ep.IsRunning()) - }) -} + require.NoError(t, ep.processConfirmedEvents(context.Background())) -func TestProcessLoopStopChannel(t *testing.T) { - logger := zerolog.Nop() - database, err := ucdb.OpenInMemoryDB(true) + // both attempted despite errors, both still CONFIRMED for retry + assert.Len(t, failing.handled, 2) + events, err := NewChainStore(database).GetConfirmedEvents(10) require.NoError(t, err) - defer database.Close() - - ep := NewEventProcessor(nil, database, "eip155:1", true, true, logger) - - t.Run("processLoop exits promptly on stop signal", func(t *testing.T) { - ctx := context.Background() - - err := ep.Start(ctx) - require.NoError(t, err) - assert.True(t, ep.IsRunning()) - - done := make(chan struct{}) - go func() { - ep.Stop() - close(done) - }() - - select { - case <-done: - // processLoop exited promptly - case <-time.After(10 * time.Second): - t.Fatal("processLoop did not exit within 10 seconds after stop signal") - } - - assert.False(t, ep.IsRunning()) - }) -} - -func TestProcessConfirmedEventsDBError(t *testing.T) { - logger := zerolog.Nop() - ctx := context.Background() - - t.Run("nil database returns error", func(t *testing.T) { - ep := &EventProcessor{ - chainStore: NewChainStore(nil), - logger: logger, - chainID: "eip155:1", - inboundEnabled: true, - outboundEnabled: true, - } - - err := ep.processConfirmedEvents(ctx) - require.Error(t, err) - assert.Contains(t, err.Error(), "failed to get confirmed events") - }) -} - -func TestEventProcessorStruct(t *testing.T) { - t.Run("struct has expected fields", func(t *testing.T) { - ep := &EventProcessor{} - assert.Nil(t, ep.signer) - assert.Nil(t, ep.chainStore) - assert.Empty(t, ep.chainID) - assert.False(t, ep.running) - assert.Nil(t, ep.stopCh) - assert.False(t, ep.inboundEnabled) - assert.False(t, ep.outboundEnabled) - }) + assert.Len(t, events, 2) } -func TestNewEventProcessorEnabledFlags(t *testing.T) { - logger := zerolog.Nop() +func TestEventProcessor_PendingEventsIgnored(t *testing.T) { + database := newTestDB(t) + ep := NewEventProcessor(database, "eip155:1", zerolog.Nop()) - t.Run("both enabled", func(t *testing.T) { - ep := NewEventProcessor(nil, nil, "eip155:1", true, true, logger) - assert.True(t, ep.inboundEnabled) - assert.True(t, ep.outboundEnabled) - }) + handler := &fakeEventHandler{} + ep.RegisterHandler(store.EventTypeInbound, handler) - t.Run("inbound only", func(t *testing.T) { - ep := NewEventProcessor(nil, nil, "eip155:1", true, false, logger) - assert.True(t, ep.inboundEnabled) - assert.False(t, ep.outboundEnabled) + result := database.Client().Create(&store.Event{ + EventID: "0xpending:0", + Type: store.EventTypeInbound, + ConfirmationType: store.ConfirmationInstant, + Status: store.StatusPending, + EventData: []byte("{}"), }) + require.NoError(t, result.Error) - t.Run("outbound only", func(t *testing.T) { - ep := NewEventProcessor(nil, nil, "eip155:1", false, true, logger) - assert.False(t, ep.inboundEnabled) - assert.True(t, ep.outboundEnabled) - }) + require.NoError(t, ep.processConfirmedEvents(context.Background())) - t.Run("both disabled", func(t *testing.T) { - ep := NewEventProcessor(nil, nil, "eip155:1", false, false, logger) - assert.False(t, ep.inboundEnabled) - assert.False(t, ep.outboundEnabled) - }) + assert.Empty(t, handler.handled) } -func TestEventProcessorStartDoubleStart(t *testing.T) { - logger := zerolog.Nop() - database, err := ucdb.OpenInMemoryDB(true) - require.NoError(t, err) - defer database.Close() - - ep := NewEventProcessor(nil, database, "eip155:1", true, true, logger) - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - // First start should succeed - err = ep.Start(ctx) - require.NoError(t, err) - assert.True(t, ep.IsRunning()) +func TestEventProcessor_NilDatabaseErrors(t *testing.T) { + ep := NewEventProcessor(nil, "eip155:1", zerolog.Nop()) + ep.RegisterHandler(store.EventTypeInbound, &fakeEventHandler{}) - // Second start should be rejected - err = ep.Start(ctx) + err := ep.processConfirmedEvents(context.Background()) require.Error(t, err) - assert.Contains(t, err.Error(), "already running") - assert.True(t, ep.IsRunning()) - - // Clean up - err = ep.Stop() - require.NoError(t, err) - assert.False(t, ep.IsRunning()) + assert.Contains(t, err.Error(), "failed to get confirmed events") } -func TestEventProcessorStopIdempotent(t *testing.T) { - logger := zerolog.Nop() - database, err := ucdb.OpenInMemoryDB(true) - require.NoError(t, err) - defer database.Close() - - ep := NewEventProcessor(nil, database, "eip155:1", true, true, logger) +func TestEventProcessor_Lifecycle(t *testing.T) { + database := newTestDB(t) + ep := NewEventProcessor(database, "eip155:1", zerolog.Nop()) ctx, cancel := context.WithCancel(context.Background()) defer cancel() - // Start the processor - err = ep.Start(ctx) - require.NoError(t, err) - assert.True(t, ep.IsRunning()) - - // First stop - err = ep.Stop() - require.NoError(t, err) - assert.False(t, ep.IsRunning()) - - // Second stop should be idempotent (no error, no panic) - err = ep.Stop() - require.NoError(t, err) - assert.False(t, ep.IsRunning()) - - // Third stop also fine - err = ep.Stop() - require.NoError(t, err) -} - -func TestEventProcessorIsRunningStateTransitions(t *testing.T) { - logger := zerolog.Nop() - database, err := ucdb.OpenInMemoryDB(true) - require.NoError(t, err) - defer database.Close() - - ep := NewEventProcessor(nil, database, "eip155:1", true, true, logger) - - // Initial state: not running + // initial state assert.False(t, ep.IsRunning()) - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - // After start: running - err = ep.Start(ctx) - require.NoError(t, err) + // start + require.NoError(t, ep.Start(ctx)) assert.True(t, ep.IsRunning()) - // After stop: not running - err = ep.Stop() - require.NoError(t, err) + // double start rejected + err := ep.Start(ctx) + require.Error(t, err) + assert.Contains(t, err.Error(), "already running") + + // stop, idempotent + require.NoError(t, ep.Stop()) assert.False(t, ep.IsRunning()) + require.NoError(t, ep.Stop()) - // Can restart after stop - err = ep.Start(ctx) - require.NoError(t, err) + // restart works + require.NoError(t, ep.Start(ctx)) assert.True(t, ep.IsRunning()) - - // Clean up - err = ep.Stop() - require.NoError(t, err) - assert.False(t, ep.IsRunning()) + require.NoError(t, ep.Stop()) } -func TestEventProcessorStopViaContextCancel(t *testing.T) { - logger := zerolog.Nop() - database, err := ucdb.OpenInMemoryDB(true) - require.NoError(t, err) - defer database.Close() - - ep := NewEventProcessor(nil, database, "eip155:1", true, true, logger) +func TestEventProcessor_StopViaContextCancel(t *testing.T) { + database := newTestDB(t) + ep := NewEventProcessor(database, "eip155:1", zerolog.Nop()) ctx, cancel := context.WithCancel(context.Background()) - - err = ep.Start(ctx) - require.NoError(t, err) + require.NoError(t, ep.Start(ctx)) assert.True(t, ep.IsRunning()) - // Cancel context - the processLoop should exit cancel() - // Stop should still work cleanly after context cancellation - err = ep.Stop() - require.NoError(t, err) + done := make(chan struct{}) + go func() { + _ = ep.Stop() + close(done) + }() + + select { + case <-done: + case <-time.After(10 * time.Second): + t.Fatal("processLoop did not exit after context cancellation") + } assert.False(t, ep.IsRunning()) } -func TestProcessConfirmedEventsEnabledFlags(t *testing.T) { - logger := zerolog.Nop() - ctx := context.Background() - - // Helper to create an in-memory DB and seed confirmed events - setupDB := func(t *testing.T, events []store.Event) *ucdb.DB { - t.Helper() - database, err := ucdb.OpenInMemoryDB(true) +func TestBase58ToHex(t *testing.T) { + t.Run("empty string returns 0x", func(t *testing.T) { + result, err := base58ToHex("") require.NoError(t, err) - for _, e := range events { - result := database.Client().Create(&e) - require.NoError(t, result.Error) - } - return database - } - - inboundEventData, _ := json.Marshal(UniversalTx{ - SourceChain: "eip155:1", - Sender: "0xsender", - Amount: "1000", - TxType: 2, + assert.Equal(t, "0x", result) }) - outboundEventData, _ := json.Marshal(OutboundEvent{ - TxID: "0xtxid", - UniversalTxID: "0xutxid", + t.Run("already hex returns as is", func(t *testing.T) { + input := "0xabcdef1234567890" + result, err := base58ToHex(input) + require.NoError(t, err) + assert.Equal(t, input, result) }) - makeEvents := func() []store.Event { - return []store.Event{ - { - EventID: "0xaaa:0", - Status: store.StatusConfirmed, - Type: store.EventTypeInbound, - EventData: inboundEventData, - }, - { - EventID: "0xbbb:0", - Status: store.StatusConfirmed, - Type: store.EventTypeOutbound, - EventData: outboundEventData, - }, - } - } - - t.Run("inbound disabled skips inbound events, leaves them CONFIRMED", func(t *testing.T) { - database := setupDB(t, makeEvents()) - // inbound=false, outbound=false (no signer so outbound will also fail to vote, but that's ok) - ep := NewEventProcessor(nil, database, "eip155:1", false, false, logger) - - err := ep.processConfirmedEvents(ctx) + t.Run("valid base58 converts to hex", func(t *testing.T) { + result, err := base58ToHex("2VfUX") require.NoError(t, err) + assert.True(t, len(result) > 2) + assert.Equal(t, "0x", result[:2]) + }) - // Inbound event should still be CONFIRMED (skipped, not processed) - var inboundEvt store.Event - database.Client().Where("event_id = ?", "0xaaa:0").First(&inboundEvt) - assert.Equal(t, store.StatusConfirmed, inboundEvt.Status) + t.Run("invalid base58 returns error", func(t *testing.T) { + // Base58 doesn't include 0, O, I, l + _, err := base58ToHex("0OIl") + require.Error(t, err) }) +} - t.Run("outbound disabled skips outbound events, leaves them CONFIRMED", func(t *testing.T) { - database := setupDB(t, makeEvents()) - ep := NewEventProcessor(nil, database, "eip155:1", false, false, logger) +func TestEventTxHash(t *testing.T) { + t.Run("hex event id", func(t *testing.T) { + assert.Equal(t, "0xabc123", eventTxHash("0xabc123:5")) + }) - err := ep.processConfirmedEvents(ctx) - require.NoError(t, err) + t.Run("base58 event id converts", func(t *testing.T) { + got := eventTxHash("2VfUX:0") + assert.Equal(t, "0x", got[:2]) + }) - // Outbound event should still be CONFIRMED (skipped, not processed) - var outboundEvt store.Event - database.Client().Where("event_id = ?", "0xbbb:0").First(&outboundEvt) - assert.Equal(t, store.StatusConfirmed, outboundEvt.Status) + t.Run("invalid base58 falls back to raw value", func(t *testing.T) { + assert.Equal(t, "0OIl", eventTxHash("0OIl:0")) }) +} - t.Run("inbound enabled but outbound disabled skips only outbound", func(t *testing.T) { - // Seed only outbound events so we don't hit nil signer panic on inbound - database := setupDB(t, []store.Event{ - { - EventID: "0xbbb:0", - Status: store.StatusConfirmed, - Type: store.EventTypeOutbound, - EventData: outboundEventData, - }, - }) - ep := NewEventProcessor(nil, database, "eip155:1", true, false, logger) +func TestMarkEventCompleted(t *testing.T) { + database := newTestDB(t) + cs := NewChainStore(database) + seedConfirmedEvent(t, database, "0xdone:0", store.EventTypeInbound, []byte("{}")) - err := ep.processConfirmedEvents(ctx) - require.NoError(t, err) + event := &store.Event{EventID: "0xdone:0", Type: store.EventTypeInbound} + require.NoError(t, markEventCompleted(cs, zerolog.Nop(), event, "0xvote")) - // Outbound event should still be CONFIRMED (skipped due to outbound disabled) - var outboundEvt store.Event - database.Client().Where("event_id = ?", "0xbbb:0").First(&outboundEvt) - assert.Equal(t, store.StatusConfirmed, outboundEvt.Status) - }) + rows, err := cs.UpdateEventStatus("0xdone:0", store.StatusCompleted, store.StatusCompleted) + require.NoError(t, err) + assert.Equal(t, int64(1), rows) - t.Run("outbound enabled but inbound disabled skips only inbound", func(t *testing.T) { - // Seed only inbound events so we don't hit nil signer panic on outbound - database := setupDB(t, []store.Event{ - { - EventID: "0xaaa:0", - Status: store.StatusConfirmed, - Type: store.EventTypeInbound, - EventData: inboundEventData, - }, - }) - ep := NewEventProcessor(nil, database, "eip155:1", false, true, logger) + // already completed: no-op, no error + require.NoError(t, markEventCompleted(cs, zerolog.Nop(), event, "0xvote2")) +} - err := ep.processConfirmedEvents(ctx) - require.NoError(t, err) +func TestEncodeUint256Result(t *testing.T) { + out, err := EncodeUint256Result(big.NewInt(1_000_000)) + require.NoError(t, err) + require.Len(t, out, 32) + assert.Equal(t, big.NewInt(1_000_000), new(big.Int).SetBytes(out)) - // Inbound event should still be CONFIRMED (skipped due to inbound disabled) - var inboundEvt store.Event - database.Client().Where("event_id = ?", "0xaaa:0").First(&inboundEvt) - assert.Equal(t, store.StatusConfirmed, inboundEvt.Status) - }) + out, err = EncodeUint256Result(nil) + require.NoError(t, err) + assert.Equal(t, make([]byte, 32), out) + + _, err = EncodeUint256Result(big.NewInt(-1)) + assert.Error(t, err) } diff --git a/universalClient/externalchains/common/inbound_observation_event_processor.go b/universalClient/externalchains/common/inbound_observation_event_processor.go new file mode 100644 index 00000000..c72f8842 --- /dev/null +++ b/universalClient/externalchains/common/inbound_observation_event_processor.go @@ -0,0 +1,133 @@ +package common + +import ( + "context" + "encoding/json" + "fmt" + "strconv" + + "github.com/pushchain/push-chain-node/universalClient/db" + "github.com/pushchain/push-chain-node/universalClient/store" + uexecutortypes "github.com/pushchain/push-chain-node/x/uexecutor/types" + "github.com/rs/zerolog" +) + +// InboundObservation is the inbound observation payload stored for INBOUND events +type InboundObservation struct { + SourceChain string `json:"sourceChain"` + LogIndex uint `json:"logIndex"` + Sender string `json:"sender"` + Recipient string `json:"recipient"` + Token string `json:"bridgeToken"` + Amount string `json:"bridgeAmount"` // uint256 as decimal string + RawPayload string `json:"rawPayload,omitempty"` // hex-encoded raw payload bytes from source chain + VerificationData string `json:"verificationData"` + RevertFundRecipient string `json:"revertFundRecipient,omitempty"` + TxType uint `json:"txType"` // enum backing uint as decimal string + FromCEA bool `json:"fromCEA"` // true if inbound is initiated by a CEA +} + +// InboundObservationEventProcessor handles INBOUND events: it builds the +// inbound observation from the stored event and votes it on Push chain. +type InboundObservationEventProcessor struct { + signer VoteSigner + chainStore *ChainStore + logger zerolog.Logger +} + +// NewInboundObservationEventProcessor creates the handler for INBOUND events. +func NewInboundObservationEventProcessor( + signer VoteSigner, + database *db.DB, + logger zerolog.Logger, +) *InboundObservationEventProcessor { + return &InboundObservationEventProcessor{ + signer: signer, + chainStore: NewChainStore(database), + logger: logger.With().Str("component", "inbound_observation_event_processor").Logger(), + } +} + +// HandleEvent implements EventHandler for INBOUND events. +func (p *InboundObservationEventProcessor) HandleEvent(ctx context.Context, event *store.Event) error { + p.logger.Debug(). + Str("event_id", event.EventID). + Msg("processing inbound event") + + // Extract inbound data from event + inbound, err := p.buildInboundObservation(event) + if err != nil { + return fmt.Errorf("failed to build inbound observation: %w", err) + } + + // Execute vote on blockchain + voteTxHash, err := p.signer.VoteInbound(ctx, inbound) + if err != nil { + return fmt.Errorf("failed to vote on inbound - keeping status for retry: %w", err) + } + + return markEventCompleted(p.chainStore, p.logger, event, voteTxHash) +} + +// buildInboundObservation builds an Inbound observation from event data +func (p *InboundObservationEventProcessor) buildInboundObservation(event *store.Event) (*uexecutortypes.Inbound, error) { + var eventData InboundObservation + + if event == nil { + return nil, fmt.Errorf("event is nil") + } + + if event.EventData == nil { + return nil, fmt.Errorf("event data is missing for event_id: %s", event.EventID) + } + + if err := json.Unmarshal(event.EventData, &eventData); err != nil { + return nil, fmt.Errorf("failed to unmarshal event data: %w", err) + } + + // Map txType from eventData to proper enum value + txType := uexecutortypes.TxType_UNSPECIFIED_TX + switch eventData.TxType { + case 0: + txType = uexecutortypes.TxType_GAS + case 1: + txType = uexecutortypes.TxType_GAS_AND_PAYLOAD + case 2: + txType = uexecutortypes.TxType_FUNDS + case 3: + txType = uexecutortypes.TxType_FUNDS_AND_PAYLOAD + default: + txType = uexecutortypes.TxType_UNSPECIFIED_TX + } + + txHashHex := eventTxHash(event.EventID) + + inboundMsg := &uexecutortypes.Inbound{ + SourceChain: eventData.SourceChain, + TxHash: txHashHex, + Sender: eventData.Sender, + Recipient: eventData.Recipient, + Amount: eventData.Amount, + AssetAddr: eventData.Token, + LogIndex: strconv.FormatUint(uint64(eventData.LogIndex), 10), + TxType: txType, + IsCEA: eventData.FromCEA, + RawPayload: eventData.RawPayload, + } + + // Set revert instructions if revert fund recipient is present + if eventData.RevertFundRecipient != "" { + inboundMsg.RevertInstructions = &uexecutortypes.RevertInstructions{ + FundRecipient: eventData.RevertFundRecipient, + } + } + + // Use event's VerificationData if present, otherwise fall back to txHash + if eventData.VerificationData == "" || eventData.VerificationData == "0x" { + inboundMsg.VerificationData = txHashHex + } else { + inboundMsg.VerificationData = eventData.VerificationData + } + + return inboundMsg, nil +} diff --git a/universalClient/externalchains/common/inbound_observation_event_processor_test.go b/universalClient/externalchains/common/inbound_observation_event_processor_test.go new file mode 100644 index 00000000..4abfe0ab --- /dev/null +++ b/universalClient/externalchains/common/inbound_observation_event_processor_test.go @@ -0,0 +1,214 @@ +package common + +import ( + "context" + "encoding/json" + "fmt" + "testing" + + "github.com/rs/zerolog" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/pushchain/push-chain-node/universalClient/store" + uexecutortypes "github.com/pushchain/push-chain-node/x/uexecutor/types" +) + +func TestInboundBuildInboundObservation(t *testing.T) { + processor := NewInboundObservationEventProcessor(nil, nil, zerolog.Nop()) + + t.Run("nil event returns error", func(t *testing.T) { + inbound, err := processor.buildInboundObservation(nil) + require.Error(t, err) + assert.Nil(t, inbound) + assert.Contains(t, err.Error(), "event is nil") + }) + + t.Run("nil event data returns error", func(t *testing.T) { + event := &store.Event{ + EventID: "0x123:0", + EventData: nil, + } + inbound, err := processor.buildInboundObservation(event) + require.Error(t, err) + assert.Nil(t, inbound) + assert.Contains(t, err.Error(), "event data is missing") + }) + + t.Run("invalid JSON returns error", func(t *testing.T) { + event := &store.Event{ + EventID: "0x123:0", + EventData: []byte("invalid json"), + } + inbound, err := processor.buildInboundObservation(event) + require.Error(t, err) + assert.Nil(t, inbound) + }) + + t.Run("valid event data constructs inbound", func(t *testing.T) { + eventData := InboundObservation{ + SourceChain: "eip155:1", + LogIndex: 5, + Sender: "0xsender123", + Recipient: "push1recipient", + Token: "0xtoken", + Amount: "1000000", + TxType: 2, // FUNDS + } + eventDataBytes, _ := json.Marshal(eventData) + + event := &store.Event{ + EventID: "0xabc123:5", + EventData: eventDataBytes, + } + + inbound, err := processor.buildInboundObservation(event) + require.NoError(t, err) + require.NotNil(t, inbound) + assert.Equal(t, "eip155:1", inbound.SourceChain) + assert.Equal(t, "0xsender123", inbound.Sender) + assert.Equal(t, "1000000", inbound.Amount) + assert.Equal(t, "0xabc123", inbound.TxHash) + assert.Equal(t, uexecutortypes.TxType_FUNDS, inbound.TxType) + }) + + t.Run("passes all fields unconditionally to inbound", func(t *testing.T) { + eventData := InboundObservation{ + SourceChain: "eip155:1", + LogIndex: 3, + Sender: "0xsender", + Recipient: "0xrecipient", + Token: "0xtoken", + Amount: "500", + RawPayload: "0xdeadbeef", + VerificationData: "0xsigdata", + RevertFundRecipient: "0xrevert", + TxType: 3, // FUNDS_AND_PAYLOAD + FromCEA: true, + } + eventDataBytes, _ := json.Marshal(eventData) + + event := &store.Event{ + EventID: "0xtxhash:3", + EventData: eventDataBytes, + } + + inbound, err := processor.buildInboundObservation(event) + require.NoError(t, err) + require.NotNil(t, inbound) + assert.Equal(t, "0xrecipient", inbound.Recipient) + assert.Equal(t, "0xdeadbeef", inbound.RawPayload) + assert.Equal(t, "0xsigdata", inbound.VerificationData) + assert.True(t, inbound.IsCEA) + require.NotNil(t, inbound.RevertInstructions) + assert.Equal(t, "0xrevert", inbound.RevertInstructions.FundRecipient) + }) + + t.Run("no revert instructions when revert recipient is empty", func(t *testing.T) { + eventData := InboundObservation{ + SourceChain: "eip155:1", + Sender: "0xsender", + Amount: "100", + TxType: 0, // GAS + RevertFundRecipient: "", + } + eventDataBytes, _ := json.Marshal(eventData) + + event := &store.Event{ + EventID: "0xhash:0", + EventData: eventDataBytes, + } + + inbound, err := processor.buildInboundObservation(event) + require.NoError(t, err) + assert.Nil(t, inbound.RevertInstructions) + }) + + t.Run("falls back verification data to tx hash", func(t *testing.T) { + eventData := InboundObservation{ + SourceChain: "eip155:1", + VerificationData: "", + TxType: 0, + } + eventDataBytes, _ := json.Marshal(eventData) + + event := &store.Event{ + EventID: "0xhash:0", + EventData: eventDataBytes, + } + + inbound, err := processor.buildInboundObservation(event) + require.NoError(t, err) + assert.Equal(t, "0xhash", inbound.VerificationData) + }) + + t.Run("tx type mapping", func(t *testing.T) { + testCases := []struct { + txType uint + expected uexecutortypes.TxType + }{ + {0, uexecutortypes.TxType_GAS}, + {1, uexecutortypes.TxType_GAS_AND_PAYLOAD}, + {2, uexecutortypes.TxType_FUNDS}, + {3, uexecutortypes.TxType_FUNDS_AND_PAYLOAD}, + {99, uexecutortypes.TxType_UNSPECIFIED_TX}, // Unknown defaults to unspecified + } + + for _, tc := range testCases { + eventData := InboundObservation{ + SourceChain: "eip155:1", + TxType: tc.txType, + } + eventDataBytes, _ := json.Marshal(eventData) + + event := &store.Event{ + EventID: "0xabc:0", + EventData: eventDataBytes, + } + + inbound, err := processor.buildInboundObservation(event) + require.NoError(t, err) + assert.Equal(t, tc.expected, inbound.TxType, "TxType %d should map to %v", tc.txType, tc.expected) + } + }) +} + +func TestInboundHandleEvent(t *testing.T) { + ctx := context.Background() + + t.Run("construct failure returns error, event stays CONFIRMED", func(t *testing.T) { + database := newTestDB(t) + processor := NewInboundObservationEventProcessor(&fakeVoteSigner{txHash: "0xvote"}, database, zerolog.Nop()) + seedConfirmedEvent(t, database, "0xbad:0", store.EventTypeInbound, []byte("not json")) + + err := processor.HandleEvent(ctx, &store.Event{EventID: "0xbad:0", EventData: []byte("not json")}) + require.Error(t, err) + assert.Contains(t, err.Error(), "failed to build inbound observation") + }) + + t.Run("vote failure returns error", func(t *testing.T) { + database := newTestDB(t) + processor := NewInboundObservationEventProcessor(&fakeVoteSigner{err: fmt.Errorf("broadcast failed")}, database, zerolog.Nop()) + eventData, _ := json.Marshal(InboundObservation{SourceChain: "eip155:1", TxType: 0}) + + err := processor.HandleEvent(ctx, &store.Event{EventID: "0xin:0", EventData: eventData}) + require.Error(t, err) + assert.Contains(t, err.Error(), "failed to vote on inbound") + }) + + t.Run("successful vote marks event completed", func(t *testing.T) { + database := newTestDB(t) + signer := &fakeVoteSigner{txHash: "0xvote"} + processor := NewInboundObservationEventProcessor(signer, database, zerolog.Nop()) + eventData, _ := json.Marshal(InboundObservation{SourceChain: "eip155:1", TxType: 0}) + seedConfirmedEvent(t, database, "0xin:0", store.EventTypeInbound, eventData) + + err := processor.HandleEvent(ctx, &store.Event{EventID: "0xin:0", Type: store.EventTypeInbound, EventData: eventData}) + require.NoError(t, err) + assert.Equal(t, 1, signer.inboundVotes) + + rows, err := NewChainStore(database).UpdateEventStatus("0xin:0", store.StatusCompleted, store.StatusCompleted) + require.NoError(t, err) + assert.Equal(t, int64(1), rows) + }) +} diff --git a/universalClient/externalchains/common/outbound_observation_event_processor.go b/universalClient/externalchains/common/outbound_observation_event_processor.go new file mode 100644 index 00000000..8ba4ee29 --- /dev/null +++ b/universalClient/externalchains/common/outbound_observation_event_processor.go @@ -0,0 +1,119 @@ +package common + +import ( + "context" + "encoding/json" + "fmt" + + "github.com/pushchain/push-chain-node/universalClient/db" + "github.com/pushchain/push-chain-node/universalClient/store" + uexecutortypes "github.com/pushchain/push-chain-node/x/uexecutor/types" + "github.com/rs/zerolog" +) + +// OutboundObservation is the outbound observation payload stored for OUTBOUND events +// Event structure: +// - txID at 1st indexed position (bytes32) +// - universalTxID at 2nd indexed position (bytes32) +type OutboundObservation struct { + TxID string `json:"tx_id"` // bytes32 hex-encoded (0x...) + UniversalTxID string `json:"universal_tx_id"` // bytes32 hex-encoded (0x...) + GasFeeUsed string `json:"gas_fee_used,omitempty"` // gas fee used in wei (decimal string) + // PC20 export only: wrapper token address deployed/minted on the destination + // at settlement (observed in the finalize event). Core uses it to flip the + // PC20 deploy flag; empty for non-PC20 settlements. + Pc20WrapperAddress string `json:"pc20_wrapper_address,omitempty"` +} + +// OutboundObservationEventProcessor handles OUTBOUND events: it builds the +// outbound observation from the stored event and votes it on Push chain. +type OutboundObservationEventProcessor struct { + signer VoteSigner + chainStore *ChainStore + logger zerolog.Logger +} + +// NewOutboundObservationEventProcessor creates the handler for OUTBOUND events. +func NewOutboundObservationEventProcessor( + signer VoteSigner, + database *db.DB, + logger zerolog.Logger, +) *OutboundObservationEventProcessor { + return &OutboundObservationEventProcessor{ + signer: signer, + chainStore: NewChainStore(database), + logger: logger.With().Str("component", "outbound_observation_event_processor").Logger(), + } +} + +// HandleEvent implements EventHandler for OUTBOUND events. +func (p *OutboundObservationEventProcessor) HandleEvent(ctx context.Context, event *store.Event) error { + p.logger.Debug(). + Str("event_id", event.EventID). + Msg("processing outbound event") + + // Parse outbound event data once + outboundData, err := p.parseOutboundEventData(event) + if err != nil { + return fmt.Errorf("failed to parse outbound event data: %w", err) + } + + // Build observation from parsed data + observation, err := p.buildOutboundObservation(event, outboundData) + if err != nil { + return fmt.Errorf("failed to build outbound observation: %w", err) + } + + // Vote on outbound + voteTxHash, err := p.signer.VoteOutbound(ctx, outboundData.TxID, outboundData.UniversalTxID, observation) + if err != nil { + return fmt.Errorf("failed to vote on outbound: %w", err) + } + + return markEventCompleted(p.chainStore, p.logger, event, voteTxHash) +} + +// parseOutboundEventData unmarshals event data into an OutboundObservation struct +func (p *OutboundObservationEventProcessor) parseOutboundEventData(event *store.Event) (*OutboundObservation, error) { + if event == nil { + return nil, fmt.Errorf("event is nil") + } + + if len(event.EventData) == 0 { + return nil, fmt.Errorf("event data is empty") + } + + var eventData OutboundObservation + if err := json.Unmarshal(event.EventData, &eventData); err != nil { + return nil, fmt.Errorf("failed to unmarshal event data: %w", err) + } + + if eventData.TxID == "" { + return nil, fmt.Errorf("tx_id not found in event data") + } + + if eventData.UniversalTxID == "" { + return nil, fmt.Errorf("universal_tx_id not found in event data") + } + + return &eventData, nil +} + +// buildOutboundObservation builds an OutboundObservation from event metadata and parsed outbound data +func (p *OutboundObservationEventProcessor) buildOutboundObservation(event *store.Event, outboundData *OutboundObservation) (*uexecutortypes.OutboundObservation, error) { + gasFeeUsed := "0" + if outboundData.GasFeeUsed != "" { + gasFeeUsed = outboundData.GasFeeUsed + } + + observation := &uexecutortypes.OutboundObservation{ + Success: true, + BlockHeight: event.BlockHeight, + TxHash: eventTxHash(event.EventID), + ErrorMsg: "", + GasFeeUsed: gasFeeUsed, + Pc20WrapperAddress: outboundData.Pc20WrapperAddress, + } + + return observation, nil +} diff --git a/universalClient/externalchains/common/outbound_observation_event_processor_test.go b/universalClient/externalchains/common/outbound_observation_event_processor_test.go new file mode 100644 index 00000000..af3db22c --- /dev/null +++ b/universalClient/externalchains/common/outbound_observation_event_processor_test.go @@ -0,0 +1,191 @@ +package common + +import ( + "context" + "encoding/json" + "fmt" + "testing" + + "github.com/rs/zerolog" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/pushchain/push-chain-node/universalClient/store" +) + +func TestOutboundParseOutboundEventData(t *testing.T) { + processor := NewOutboundObservationEventProcessor(nil, nil, zerolog.Nop()) + + t.Run("nil event returns error", func(t *testing.T) { + data, err := processor.parseOutboundEventData(nil) + require.Error(t, err) + assert.Nil(t, data) + assert.Contains(t, err.Error(), "event is nil") + }) + + t.Run("empty event data returns error", func(t *testing.T) { + event := &store.Event{ + EventID: "test", + EventData: []byte{}, + } + data, err := processor.parseOutboundEventData(event) + require.Error(t, err) + assert.Nil(t, data) + assert.Contains(t, err.Error(), "event data is empty") + }) + + t.Run("valid outbound event extracts IDs and gas fee", func(t *testing.T) { + eventData := OutboundObservation{ + TxID: "0x1234", + UniversalTxID: "0xabcd", + GasFeeUsed: "42000000000000", + } + eventDataBytes, _ := json.Marshal(eventData) + + event := &store.Event{ + EventID: "test", + EventData: eventDataBytes, + } + + data, err := processor.parseOutboundEventData(event) + require.NoError(t, err) + assert.Equal(t, "0x1234", data.TxID) + assert.Equal(t, "0xabcd", data.UniversalTxID) + assert.Equal(t, "42000000000000", data.GasFeeUsed) + }) + + t.Run("missing tx_id returns error", func(t *testing.T) { + eventData := OutboundObservation{ + TxID: "", + UniversalTxID: "0xabcd", + } + eventDataBytes, _ := json.Marshal(eventData) + + event := &store.Event{ + EventID: "test", + EventData: eventDataBytes, + } + + data, err := processor.parseOutboundEventData(event) + require.Error(t, err) + assert.Nil(t, data) + assert.Contains(t, err.Error(), "tx_id not found") + }) + + t.Run("missing universal_tx_id returns error", func(t *testing.T) { + eventData := OutboundObservation{ + TxID: "0x1234", + UniversalTxID: "", + } + eventDataBytes, _ := json.Marshal(eventData) + + event := &store.Event{ + EventID: "test", + EventData: eventDataBytes, + } + + data, err := processor.parseOutboundEventData(event) + require.Error(t, err) + assert.Nil(t, data) + assert.Contains(t, err.Error(), "universal_tx_id not found") + }) +} + +func TestOutboundBuildOutboundObservation(t *testing.T) { + processor := NewOutboundObservationEventProcessor(nil, nil, zerolog.Nop()) + + t.Run("builds observation with gas fee from parsed data", func(t *testing.T) { + outboundData := &OutboundObservation{ + TxID: "0x1234", + UniversalTxID: "0xabcd", + GasFeeUsed: "42000000000000", + } + + event := &store.Event{ + EventID: "0xabc123:5", + BlockHeight: 12345, + } + + obs, err := processor.buildOutboundObservation(event, outboundData) + require.NoError(t, err) + require.NotNil(t, obs) + assert.True(t, obs.Success) + assert.Equal(t, uint64(12345), obs.BlockHeight) + assert.Equal(t, "0xabc123", obs.TxHash) + assert.Equal(t, "42000000000000", obs.GasFeeUsed) + }) + + t.Run("missing gas fee defaults to 0", func(t *testing.T) { + outboundData := &OutboundObservation{ + TxID: "0x1234", + UniversalTxID: "0xabcd", + } + + event := &store.Event{ + EventID: "0xabc123:5", + BlockHeight: 12345, + } + + obs, err := processor.buildOutboundObservation(event, outboundData) + require.NoError(t, err) + require.NotNil(t, obs) + assert.Equal(t, "0", obs.GasFeeUsed) + }) + + t.Run("handles base58 tx hash", func(t *testing.T) { + outboundData := &OutboundObservation{ + TxID: "0x1234", + UniversalTxID: "0xabcd", + } + + event := &store.Event{ + EventID: "2VfUX:0", // Base58 encoded + BlockHeight: 100, + } + + obs, err := processor.buildOutboundObservation(event, outboundData) + require.NoError(t, err) + require.NotNil(t, obs) + assert.True(t, len(obs.TxHash) >= 2) + assert.Equal(t, "0x", obs.TxHash[:2]) + }) +} + +func TestOutboundHandleEvent(t *testing.T) { + ctx := context.Background() + + t.Run("parse failure returns error", func(t *testing.T) { + database := newTestDB(t) + processor := NewOutboundObservationEventProcessor(&fakeVoteSigner{txHash: "0xvote"}, database, zerolog.Nop()) + + err := processor.HandleEvent(ctx, &store.Event{EventID: "0xbad:0", EventData: []byte("not json")}) + require.Error(t, err) + assert.Contains(t, err.Error(), "failed to parse outbound event data") + }) + + t.Run("vote failure returns error", func(t *testing.T) { + database := newTestDB(t) + processor := NewOutboundObservationEventProcessor(&fakeVoteSigner{err: fmt.Errorf("broadcast failed")}, database, zerolog.Nop()) + eventData, _ := json.Marshal(OutboundObservation{TxID: "0xtxid", UniversalTxID: "0xutxid"}) + + err := processor.HandleEvent(ctx, &store.Event{EventID: "0xout:0", EventData: eventData}) + require.Error(t, err) + assert.Contains(t, err.Error(), "failed to vote on outbound") + }) + + t.Run("successful vote marks event completed", func(t *testing.T) { + database := newTestDB(t) + signer := &fakeVoteSigner{txHash: "0xvote"} + processor := NewOutboundObservationEventProcessor(signer, database, zerolog.Nop()) + eventData, _ := json.Marshal(OutboundObservation{TxID: "0xtxid", UniversalTxID: "0xutxid"}) + seedConfirmedEvent(t, database, "0xout:0", store.EventTypeOutbound, eventData) + + err := processor.HandleEvent(ctx, &store.Event{EventID: "0xout:0", Type: store.EventTypeOutbound, EventData: eventData}) + require.NoError(t, err) + assert.Equal(t, 1, signer.outboundVotes) + + rows, err := NewChainStore(database).UpdateEventStatus("0xout:0", store.StatusCompleted, store.StatusCompleted) + require.NoError(t, err) + assert.Equal(t, int64(1), rows) + }) +} diff --git a/universalClient/externalchains/common/types.go b/universalClient/externalchains/common/types.go index f3b2317c..6f258f52 100644 --- a/universalClient/externalchains/common/types.go +++ b/universalClient/externalchains/common/types.go @@ -2,11 +2,29 @@ package common import ( "context" + "fmt" "math/big" + ucallbacktypes "github.com/pushchain/push-chain-node/x/ucallback/types" uetypes "github.com/pushchain/push-chain-node/x/uexecutor/types" ) +// EncodeUint256Result canonically encodes a balance/amount as abi.encode(uint256) +// so read results are byte-identical across validators and decodable by the +// requesting contract. The bounds check guards against a malicious RPC value +// that would not fit (FillBytes panics on overflow). +func EncodeUint256Result(v *big.Int) ([]byte, error) { + if v == nil { + v = big.NewInt(0) + } + if v.Sign() < 0 || v.BitLen() > 256 { + return nil, fmt.Errorf("value out of uint256 range") + } + out := make([]byte, 32) + v.FillBytes(out) + return out, nil +} + // ChainClient defines the interface for chain-specific implementations type ChainClient interface { // Start initializes and starts the chain client @@ -21,6 +39,11 @@ type ChainClient interface { // GetTxBuilder returns the TxBuilder for this chain // Returns an error if txBuilder is not supported for this chain (e.g., Push chain) GetTxBuilder() (TxBuilder, error) + + // GetReadRequestHandler returns the handler executing read requests + // destined for this chain + // Returns an error if reads are not available (e.g. client not started) + GetReadRequestHandler() (ReadRequestHandler, error) } // FundMigrationData contains the data needed to build a fund migration transaction. @@ -91,32 +114,18 @@ type TxBuilder interface { BroadcastFundMigrationTx(ctx context.Context, req *UnsignedSigningReq, data *FundMigrationData, signature []byte) (string, error) } -// UniversalTx Payload -type UniversalTx struct { - SourceChain string `json:"sourceChain"` - LogIndex uint `json:"logIndex"` - Sender string `json:"sender"` - Recipient string `json:"recipient"` - Token string `json:"bridgeToken"` - Amount string `json:"bridgeAmount"` // uint256 as decimal string - RawPayload string `json:"rawPayload,omitempty"` // hex-encoded raw payload bytes from source chain - VerificationData string `json:"verificationData"` - RevertFundRecipient string `json:"revertFundRecipient,omitempty"` - TxType uint `json:"txType"` // enum backing uint as decimal string - FromCEA bool `json:"fromCEA"` // true if inbound is initiated by a CEA +// ReadRequestHandler executes a read request on one destination chain. +// Consumed by the push watcher's read processor. +type ReadRequestHandler interface { + ExecuteRead(ctx context.Context, req *ucallbacktypes.ReadRequest) (*ucallbacktypes.ReadResult, error) } -// OutboundEvent represents an outbound observation event from the gateway contract -// Event structure: -// - txID at 1st indexed position (bytes32) -// - universalTxID at 2nd indexed position (bytes32) -type OutboundEvent struct { - TxID string `json:"tx_id"` // bytes32 hex-encoded (0x...) - UniversalTxID string `json:"universal_tx_id"` // bytes32 hex-encoded (0x...) - GasFeeUsed string `json:"gas_fee_used,omitempty"` // gas fee used in wei (decimal string) - // PC20 export only: wrapper token address deployed/minted on the destination - // at settlement (observed in the finalize event). Core uses it to flip the - // PC20 deploy flag; empty for non-PC20 settlements. - Pc20WrapperAddress string `json:"pc20_wrapper_address,omitempty"` +// NewReadErrorResult builds an ERROR observation carrying a deterministic error +// code. ResultData stays empty and only the code (never local error text) is +// voted, so every validator observing the same failure converges on one ballot. +func NewReadErrorResult(code ucallbacktypes.ReadErrorCode) *ucallbacktypes.ReadResult { + return &ucallbacktypes.ReadResult{ + Status: ucallbacktypes.ReadStatus_READ_STATUS_ERROR, + ErrorCode: code, + } } - diff --git a/universalClient/externalchains/evm/client.go b/universalClient/externalchains/evm/client.go index 36ada6f9..43e3ece4 100644 --- a/universalClient/externalchains/evm/client.go +++ b/universalClient/externalchains/evm/client.go @@ -14,6 +14,7 @@ import ( "github.com/pushchain/push-chain-node/universalClient/db" "github.com/pushchain/push-chain-node/universalClient/externalchains/common" "github.com/pushchain/push-chain-node/universalClient/pushsigner" + "github.com/pushchain/push-chain-node/universalClient/store" uregistrytypes "github.com/pushchain/push-chain-node/x/uregistry/types" ) @@ -86,16 +87,14 @@ func NewClient( // Initialize components that don't require RPC client if pushSigner != nil { - inboundEnabled := config.Enabled != nil && config.Enabled.IsInboundEnabled - outboundEnabled := config.Enabled != nil && config.Enabled.IsOutboundEnabled - client.eventProcessor = common.NewEventProcessor( - pushSigner, - database, - chainIDStr, - inboundEnabled, - outboundEnabled, - log, - ) + ep := common.NewEventProcessor(database, chainIDStr, log) + if config.Enabled != nil && config.Enabled.IsInboundEnabled { + ep.RegisterHandler(store.EventTypeInbound, common.NewInboundObservationEventProcessor(pushSigner, database, log)) + } + if config.Enabled != nil && config.Enabled.IsOutboundEnabled { + ep.RegisterHandler(store.EventTypeOutbound, common.NewOutboundObservationEventProcessor(pushSigner, database, log)) + } + client.eventProcessor = ep } return client, nil @@ -199,6 +198,14 @@ func (c *Client) GetTxBuilder() (common.TxBuilder, error) { return c.txBuilder, nil } +// GetReadRequestHandler returns the read request handler for this chain +func (c *Client) GetReadRequestHandler() (common.ReadRequestHandler, error) { + if c.rpcClient == nil { + return nil, fmt.Errorf("read handler not available for chain %s (client not started)", c.chainIDStr) + } + return c, nil +} + // initializeComponents creates all components that require the RPC client func (c *Client) initializeComponents() error { // Create event listener if gateway is configured diff --git a/universalClient/externalchains/evm/event_confirmer.go b/universalClient/externalchains/evm/event_confirmer.go index 45cabc08..b4c73a83 100644 --- a/universalClient/externalchains/evm/event_confirmer.go +++ b/universalClient/externalchains/evm/event_confirmer.go @@ -181,7 +181,7 @@ func (ec *EventConfirmer) processPendingEvents(ctx context.Context) error { gasFeeUsed := new(big.Int).Mul(gasUsed, gasPrice).String() // Unmarshal, set GasFeeUsed, re-marshal - var outboundEvent chaincommon.OutboundEvent + var outboundEvent chaincommon.OutboundObservation if unmarshalErr := json.Unmarshal(event.EventData, &outboundEvent); unmarshalErr != nil { ec.logger.Error(). Err(unmarshalErr). diff --git a/universalClient/externalchains/evm/event_confirmer_test.go b/universalClient/externalchains/evm/event_confirmer_test.go index 022812cb..55ae7f51 100644 --- a/universalClient/externalchains/evm/event_confirmer_test.go +++ b/universalClient/externalchains/evm/event_confirmer_test.go @@ -313,7 +313,7 @@ func TestEventConfirmer_UpdateStatusAndEventData_WithDB(t *testing.T) { _, memDB := newTestEventConfirmerWithDB(t) cs := common.NewChainStore(memDB) - outbound := common.OutboundEvent{ + outbound := common.OutboundObservation{ TxID: "0xtx1", UniversalTxID: "0xuni1", } @@ -347,7 +347,7 @@ func TestEventConfirmer_UpdateStatusAndEventData_WithDB(t *testing.T) { require.Len(t, confirmed, 1) assert.Equal(t, "0xoutbound1:0", confirmed[0].EventID) - var stored common.OutboundEvent + var stored common.OutboundObservation require.NoError(t, json.Unmarshal(confirmed[0].EventData, &stored)) assert.Equal(t, "123456789", stored.GasFeeUsed) } diff --git a/universalClient/externalchains/evm/event_parser.go b/universalClient/externalchains/evm/event_parser.go index 3d44d470..a603f8ad 100644 --- a/universalClient/externalchains/evm/event_parser.go +++ b/universalClient/externalchains/evm/event_parser.go @@ -125,7 +125,7 @@ func parseOutboundObservationEvent(log *types.Log, eventType string, logger zero } // Create OutboundEvent payload - payload := common.OutboundEvent{ + payload := common.OutboundObservation{ TxID: txID, UniversalTxID: universalTxID, Pc20WrapperAddress: wrapperAddr, @@ -168,7 +168,7 @@ func parseUniversalTxEvent(event *store.Event, log *types.Log, chainID string, l return } - payload := common.UniversalTx{ + payload := common.InboundObservation{ SourceChain: chainID, Sender: ethcommon.BytesToAddress(log.Topics[1].Bytes()).Hex(), Recipient: ethcommon.BytesToAddress(log.Topics[2].Bytes()).Hex(), @@ -215,7 +215,7 @@ func readWord(data []byte, i int) []byte { // decodePayload reads the raw payload bytes at the given offset and stores the hex string. // The core validator will decode the universal payload from these raw bytes. -func decodePayload(data []byte, dataOffset uint64, payload *common.UniversalTx, logger zerolog.Logger) { +func decodePayload(data []byte, dataOffset uint64, payload *common.InboundObservation, logger zerolog.Logger) { if dataOffset < uint64(32*5) { return } @@ -240,7 +240,7 @@ func decodeSignatureData(data []byte, w []byte, minOffset uint64) string { } // finalizeEvent marshals the payload and sets confirmation type on the event. -func finalizeEvent(event *store.Event, payload *common.UniversalTx, logger zerolog.Logger) { +func finalizeEvent(event *store.Event, payload *common.InboundObservation, logger zerolog.Logger) { if b, err := json.Marshal(payload); err == nil { event.EventData = b } else { @@ -266,7 +266,7 @@ UniversalTx Event (V2 - upgraded chains): - signatureData (bytes) — Word 5 (offset) - fromCEA (bool) — Word 6 */ -func parseUniversalTx(event *store.Event, log *types.Log, dataOffset uint64, payload *common.UniversalTx, logger zerolog.Logger) { +func parseUniversalTx(event *store.Event, log *types.Log, dataOffset uint64, payload *common.InboundObservation, logger zerolog.Logger) { data := log.Data decodePayload(data, dataOffset, payload, logger) diff --git a/universalClient/externalchains/evm/event_parser_test.go b/universalClient/externalchains/evm/event_parser_test.go index 9fb77e1e..88dbc878 100644 --- a/universalClient/externalchains/evm/event_parser_test.go +++ b/universalClient/externalchains/evm/event_parser_test.go @@ -337,7 +337,7 @@ func TestParseOutboundObservation_PC20Wrapper(t *testing.T) { wrapperOf := func(t *testing.T, e *store.Event) string { t.Helper() - var ob common.OutboundEvent + var ob common.OutboundObservation require.NoError(t, json.Unmarshal(e.EventData, &ob)) return ob.Pc20WrapperAddress } @@ -544,21 +544,21 @@ func TestDecodePayload(t *testing.T) { big.NewInt(int64(len(inner))).FillBytes(data[160:192]) copy(data[192:196], inner) - payload := &common.UniversalTx{} + payload := &common.InboundObservation{} decodePayload(data, 160, payload, logger) assert.Equal(t, "0xdeadbeef", payload.RawPayload) }) t.Run("offset too small is ignored", func(t *testing.T) { data := make([]byte, 256) - payload := &common.UniversalTx{} + payload := &common.InboundObservation{} decodePayload(data, 32, payload, logger) // < 32*5 assert.Empty(t, payload.RawPayload) }) t.Run("offset zero is ignored", func(t *testing.T) { data := make([]byte, 256) - payload := &common.UniversalTx{} + payload := &common.InboundObservation{} decodePayload(data, 0, payload, logger) assert.Empty(t, payload.RawPayload) }) @@ -566,7 +566,7 @@ func TestDecodePayload(t *testing.T) { t.Run("readDynamicBytes fails gracefully", func(t *testing.T) { // Data is too short for the length word at the offset data := make([]byte, 168) // offset 160 + only 8 bytes; need 32 for length - payload := &common.UniversalTx{} + payload := &common.InboundObservation{} decodePayload(data, 160, payload, logger) assert.Empty(t, payload.RawPayload) }) @@ -634,13 +634,13 @@ func TestFinalizeEvent(t *testing.T) { t.Run("txType 0 sets FAST confirmation", func(t *testing.T) { event := &store.Event{} - payload := &common.UniversalTx{TxType: 0, Sender: "0xabc"} + payload := &common.InboundObservation{TxType: 0, Sender: "0xabc"} finalizeEvent(event, payload, logger) assert.Equal(t, store.ConfirmationFast, event.ConfirmationType) assert.NotNil(t, event.EventData) - var decoded common.UniversalTx + var decoded common.InboundObservation err := json.Unmarshal(event.EventData, &decoded) require.NoError(t, err) assert.Equal(t, "0xabc", decoded.Sender) @@ -648,7 +648,7 @@ func TestFinalizeEvent(t *testing.T) { t.Run("txType 1 sets FAST confirmation", func(t *testing.T) { event := &store.Event{} - payload := &common.UniversalTx{TxType: 1} + payload := &common.InboundObservation{TxType: 1} finalizeEvent(event, payload, logger) assert.Equal(t, store.ConfirmationFast, event.ConfirmationType) @@ -656,7 +656,7 @@ func TestFinalizeEvent(t *testing.T) { t.Run("txType 2 sets STANDARD confirmation", func(t *testing.T) { event := &store.Event{} - payload := &common.UniversalTx{TxType: 2} + payload := &common.InboundObservation{TxType: 2} finalizeEvent(event, payload, logger) assert.Equal(t, store.ConfirmationStandard, event.ConfirmationType) @@ -664,7 +664,7 @@ func TestFinalizeEvent(t *testing.T) { t.Run("txType 3 sets STANDARD confirmation", func(t *testing.T) { event := &store.Event{} - payload := &common.UniversalTx{TxType: 3} + payload := &common.InboundObservation{TxType: 3} finalizeEvent(event, payload, logger) assert.Equal(t, store.ConfirmationStandard, event.ConfirmationType) @@ -672,7 +672,7 @@ func TestFinalizeEvent(t *testing.T) { t.Run("high txType sets STANDARD confirmation", func(t *testing.T) { event := &store.Event{} - payload := &common.UniversalTx{TxType: 255} + payload := &common.InboundObservation{TxType: 255} finalizeEvent(event, payload, logger) assert.Equal(t, store.ConfirmationStandard, event.ConfirmationType) @@ -680,7 +680,7 @@ func TestFinalizeEvent(t *testing.T) { t.Run("event data is valid JSON", func(t *testing.T) { event := &store.Event{} - payload := &common.UniversalTx{ + payload := &common.InboundObservation{ SourceChain: "eip155:1", Sender: "0xsender", Recipient: "0xrecipient", @@ -690,7 +690,7 @@ func TestFinalizeEvent(t *testing.T) { } finalizeEvent(event, payload, logger) - var decoded common.UniversalTx + var decoded common.InboundObservation err := json.Unmarshal(event.EventData, &decoded) require.NoError(t, err) assert.Equal(t, "eip155:1", decoded.SourceChain) diff --git a/universalClient/externalchains/evm/read_envelope.go b/universalClient/externalchains/evm/read_envelope.go new file mode 100644 index 00000000..428ce66c --- /dev/null +++ b/universalClient/externalchains/evm/read_envelope.go @@ -0,0 +1,120 @@ +package evm + +import ( + "fmt" + + "github.com/ethereum/go-ethereum/accounts/abi" + ethcommon "github.com/ethereum/go-ethereum/common" +) + +// evmQueryType mirrors the EvmQueryEnvelope enum from the read spec. +type evmQueryType uint8 + +const ( + evmQueryAccountBalance evmQueryType = 0 + evmQueryContractCall evmQueryType = 1 + evmQueryStorageSlot evmQueryType = 2 +) + +// evmBlockRefType mirrors the EvmBlockRefType enum. Only AT_NUMBER exists in v1. +type evmBlockRefType uint8 + +const evmBlockRefAtNumber evmBlockRefType = 0 + +// evmQueryEnvelope is the decoded abi.encode(EvmQueryEnvelope) query. +type evmQueryEnvelope struct { + QueryType evmQueryType + RefType evmBlockRefType + BlockNumber uint64 + Payload []byte +} + +var ( + evmEnvelopeArgs = mustReadArgs(abi.ArgumentMarshaling{Type: "tuple", Components: []abi.ArgumentMarshaling{ + {Name: "queryType", Type: "uint8"}, + {Name: "blockRef", Type: "tuple", Components: []abi.ArgumentMarshaling{ + {Name: "refType", Type: "uint8"}, + {Name: "blockNumber", Type: "uint64"}, + }}, + {Name: "payload", Type: "bytes"}, + }}) + + addressArgs = mustReadArgs(abi.ArgumentMarshaling{Type: "address"}) + addressBytesArgs = mustReadArgs(abi.ArgumentMarshaling{Type: "address"}, abi.ArgumentMarshaling{Type: "bytes"}) + addressBytes32Args = mustReadArgs(abi.ArgumentMarshaling{Type: "address"}, abi.ArgumentMarshaling{Type: "bytes32"}) +) + +func mustReadArgs(marshalings ...abi.ArgumentMarshaling) abi.Arguments { + args := make(abi.Arguments, 0, len(marshalings)) + for i, m := range marshalings { + if m.Name == "" { + m.Name = fmt.Sprintf("arg%d", i) + } + typ, err := abi.NewType(m.Type, "", m.Components) + if err != nil { + panic(fmt.Sprintf("evm: invalid abi type %q: %v", m.Type, err)) + } + args = append(args, abi.Argument{Name: m.Name, Type: typ}) + } + return args +} + +type rawEvmEnvelope struct { + QueryType uint8 + BlockRef struct { + RefType uint8 + BlockNumber uint64 + } + Payload []byte +} + +// decodeEvmQueryEnvelope decodes ReadSpec.query for eip155 chains. +func decodeEvmQueryEnvelope(query []byte) (*evmQueryEnvelope, error) { + vals, err := evmEnvelopeArgs.Unpack(query) + if err != nil { + return nil, fmt.Errorf("failed to unpack EvmQueryEnvelope: %w", err) + } + raw := *abi.ConvertType(vals[0], new(rawEvmEnvelope)).(*rawEvmEnvelope) + + env := &evmQueryEnvelope{ + QueryType: evmQueryType(raw.QueryType), + RefType: evmBlockRefType(raw.BlockRef.RefType), + BlockNumber: raw.BlockRef.BlockNumber, + Payload: raw.Payload, + } + if env.QueryType > evmQueryStorageSlot { + return nil, fmt.Errorf("unknown EvmQueryType %d", env.QueryType) + } + if env.RefType != evmBlockRefAtNumber { + return nil, fmt.Errorf("unsupported EvmBlockRefType %d", env.RefType) + } + return env, nil +} + +// decodeAccountBalancePayload decodes abi.encode(address target). +func decodeAccountBalancePayload(payload []byte) (ethcommon.Address, error) { + vals, err := addressArgs.Unpack(payload) + if err != nil { + return ethcommon.Address{}, fmt.Errorf("failed to unpack AccountBalance payload: %w", err) + } + return vals[0].(ethcommon.Address), nil +} + +// decodeContractCallPayload decodes abi.encode(address target, bytes callData). +func decodeContractCallPayload(payload []byte) (ethcommon.Address, []byte, error) { + vals, err := addressBytesArgs.Unpack(payload) + if err != nil { + return ethcommon.Address{}, nil, fmt.Errorf("failed to unpack ContractCall payload: %w", err) + } + return vals[0].(ethcommon.Address), vals[1].([]byte), nil +} + +// decodeStorageSlotPayload decodes abi.encode(address contractAddr, bytes32 slot). +func decodeStorageSlotPayload(payload []byte) (ethcommon.Address, ethcommon.Hash, error) { + vals, err := addressBytes32Args.Unpack(payload) + if err != nil { + return ethcommon.Address{}, ethcommon.Hash{}, fmt.Errorf("failed to unpack StorageSlot payload: %w", err) + } + slot := vals[1].([32]byte) + return vals[0].(ethcommon.Address), ethcommon.Hash(slot), nil +} diff --git a/universalClient/externalchains/evm/read_envelope_test.go b/universalClient/externalchains/evm/read_envelope_test.go new file mode 100644 index 00000000..5d07e7d4 --- /dev/null +++ b/universalClient/externalchains/evm/read_envelope_test.go @@ -0,0 +1,72 @@ +package evm + +import ( + "testing" + + ethcommon "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func packEvmEnvelope(t *testing.T, queryType, refType uint8, blockNumber uint64, payload []byte) []byte { + t.Helper() + data, err := evmEnvelopeArgs.Pack(rawEvmEnvelope{ + QueryType: queryType, + BlockRef: struct { + RefType uint8 + BlockNumber uint64 + }{refType, blockNumber}, + Payload: payload, + }) + require.NoError(t, err) + return data +} + +func TestDecodeEvmQueryEnvelope(t *testing.T) { + target := ethcommon.HexToAddress("0x1111111111111111111111111111111111111111") + payload, err := addressArgs.Pack(target) + require.NoError(t, err) + + env, err := decodeEvmQueryEnvelope(packEvmEnvelope(t, uint8(evmQueryAccountBalance), 0, 1234, payload)) + require.NoError(t, err) + assert.Equal(t, evmQueryAccountBalance, env.QueryType) + assert.Equal(t, evmBlockRefAtNumber, env.RefType) + assert.Equal(t, uint64(1234), env.BlockNumber) + + decoded, err := decodeAccountBalancePayload(env.Payload) + require.NoError(t, err) + assert.Equal(t, target, decoded) +} + +func TestDecodeEvmQueryEnvelope_Invalid(t *testing.T) { + _, err := decodeEvmQueryEnvelope([]byte{0x01, 0x02}) + assert.Error(t, err) + + // unknown query type + _, err = decodeEvmQueryEnvelope(packEvmEnvelope(t, 9, 0, 0, nil)) + assert.Error(t, err) + + // unknown block ref type + _, err = decodeEvmQueryEnvelope(packEvmEnvelope(t, 0, 7, 0, nil)) + assert.Error(t, err) +} + +func TestDecodeEvmPayloads(t *testing.T) { + token := ethcommon.HexToAddress("0x2222222222222222222222222222222222222222") + + callData := []byte{0xde, 0xad, 0xbe, 0xef} + callPayload, err := addressBytesArgs.Pack(token, callData) + require.NoError(t, err) + gotTarget, gotData, err := decodeContractCallPayload(callPayload) + require.NoError(t, err) + assert.Equal(t, token, gotTarget) + assert.Equal(t, callData, gotData) + + slot := [32]byte{0x0a} + slotPayload, err := addressBytes32Args.Pack(token, slot) + require.NoError(t, err) + gotAddr, gotSlot, err := decodeStorageSlotPayload(slotPayload) + require.NoError(t, err) + assert.Equal(t, token, gotAddr) + assert.Equal(t, ethcommon.Hash(slot), gotSlot) +} diff --git a/universalClient/externalchains/evm/read_executor.go b/universalClient/externalchains/evm/read_executor.go new file mode 100644 index 00000000..2ee2f6ac --- /dev/null +++ b/universalClient/externalchains/evm/read_executor.go @@ -0,0 +1,123 @@ +package evm + +import ( + "context" + "errors" + "fmt" + "math/big" + "strings" + + "github.com/ethereum/go-ethereum/rpc" + + "github.com/pushchain/push-chain-node/universalClient/externalchains/common" + ucallbacktypes "github.com/pushchain/push-chain-node/x/ucallback/types" +) + +// ExecuteRead implements common.ChainReader for EVM chains. +// All validators must produce byte-identical results, so every query runs at the +// height pinned in the request; execution is gated until that height has +// min_confirmations confirmations so a reorg cannot invalidate the read. +func (c *Client) ExecuteRead(ctx context.Context, req *ucallbacktypes.ReadRequest) (*ucallbacktypes.ReadResult, error) { + env, err := decodeEvmQueryEnvelope(req.Query) + if err != nil { + return common.NewReadErrorResult(ucallbacktypes.ReadErrorCode_READ_ERROR_INVALID_QUERY), nil + } + + height := req.DestinationBlockHeight + if height == 0 { + height = env.BlockNumber + } + if height == 0 { + return common.NewReadErrorResult(ucallbacktypes.ReadErrorCode_READ_ERROR_INVALID_QUERY), nil + } + + if err := c.gateHeightConfirmed(ctx, height, uint64(req.MinConfirmations)); err != nil { + return nil, err + } + blockNum := new(big.Int).SetUint64(height) + + var resultData []byte + switch env.QueryType { + case evmQueryAccountBalance: + target, decErr := decodeAccountBalancePayload(env.Payload) + if decErr != nil { + return common.NewReadErrorResult(ucallbacktypes.ReadErrorCode_READ_ERROR_INVALID_QUERY), nil + } + balance, rpcErr := c.rpcClient.GetBalanceAt(ctx, target, blockNum) + if rpcErr != nil { + return nil, rpcErr + } + resultData, err = common.EncodeUint256Result(balance) + + case evmQueryContractCall: + target, callData, decErr := decodeContractCallPayload(env.Payload) + if decErr != nil { + return common.NewReadErrorResult(ucallbacktypes.ReadErrorCode_READ_ERROR_INVALID_QUERY), nil + } + ret, rpcErr := c.rpcClient.CallContract(ctx, target, callData, blockNum) + if rpcErr != nil { + // Only a genuine execution revert is deterministic at the pinned + // height and safe to vote. A transport error or a node-state error + // (e.g. missing trie node on a pruned node) is not deterministic and + // must be retried, never voted. + if isExecutionRevert(rpcErr) { + return common.NewReadErrorResult(ucallbacktypes.ReadErrorCode_READ_ERROR_REVERTED), nil + } + return nil, rpcErr + } + resultData = ret + + case evmQueryStorageSlot: + target, slot, decErr := decodeStorageSlotPayload(env.Payload) + if decErr != nil { + return common.NewReadErrorResult(ucallbacktypes.ReadErrorCode_READ_ERROR_INVALID_QUERY), nil + } + value, rpcErr := c.rpcClient.GetStorageAt(ctx, target, slot, blockNum) + if rpcErr != nil { + return nil, rpcErr + } + var slotValue [32]byte + copy(slotValue[32-min(len(value), 32):], value) + resultData = slotValue[:] + + default: + return common.NewReadErrorResult(ucallbacktypes.ReadErrorCode_READ_ERROR_INVALID_QUERY), nil + } + if err != nil { + return common.NewReadErrorResult(ucallbacktypes.ReadErrorCode_READ_ERROR_INVALID_RESULT), nil + } + + return &ucallbacktypes.ReadResult{ + Status: ucallbacktypes.ReadStatus_READ_STATUS_SUCCESS, + ResultData: resultData, + }, nil +} + +// isExecutionRevert reports whether an eth_call error is a deterministic EVM +// revert (the node executed the call and it reverted) rather than a transient +// transport or node-state failure. Only a revert is safe to vote as ERROR. +func isExecutionRevert(err error) bool { + var dataErr rpc.DataError + if errors.As(err, &dataErr) && dataErr.ErrorData() != nil { + return true + } + var rpcErr rpc.Error + if errors.As(err, &rpcErr) && rpcErr.ErrorCode() == 3 { + return true + } + return strings.Contains(strings.ToLower(err.Error()), "execution reverted") +} + +// gateHeightConfirmed blocks execution until the target height has at least +// minConfirmations confirmations. An error is transient: the processor keeps +// the event CONFIRMED and retries next tick. +func (c *Client) gateHeightConfirmed(ctx context.Context, height, minConfirmations uint64) error { + latest, err := c.rpcClient.GetLatestBlock(ctx) + if err != nil { + return fmt.Errorf("failed to get latest block: %w", err) + } + if latest < height+minConfirmations { + return fmt.Errorf("height %d needs %d confirmations, chain at %d; not final yet", height, minConfirmations, latest) + } + return nil +} diff --git a/universalClient/externalchains/evm/read_executor_test.go b/universalClient/externalchains/evm/read_executor_test.go new file mode 100644 index 00000000..993b7b45 --- /dev/null +++ b/universalClient/externalchains/evm/read_executor_test.go @@ -0,0 +1,315 @@ +package evm + +import ( + "context" + "encoding/json" + "fmt" + "math/big" + "net/http" + "net/http/httptest" + "testing" + + ethcommon "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/rs/zerolog" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + ucallbacktypes "github.com/pushchain/push-chain-node/x/ucallback/types" +) + +// fakeHeader is a minimal valid block header JSON accepted by types.Header. +func fakeHeader(number uint64) map[string]any { + zeroHash := "0x0000000000000000000000000000000000000000000000000000000000000000" + return map[string]any{ + "parentHash": zeroHash, + "sha3Uncles": zeroHash, + "miner": "0x0000000000000000000000000000000000000000", + "stateRoot": zeroHash, + "transactionsRoot": zeroHash, + "receiptsRoot": zeroHash, + "logsBloom": "0x" + fmt.Sprintf("%0512x", 0), + "difficulty": "0x0", + "number": fmt.Sprintf("0x%x", number), + "gasLimit": "0x0", + "gasUsed": "0x0", + "timestamp": "0x0", + "extraData": "0x", + "mixHash": zeroHash, + "nonce": "0x0000000000000000", + } +} + +type rpcFault struct { + code int + message string +} + +// newReadTestClient spins up a JSON-RPC server answering from results/faults +// keyed by method name, and returns a Client wired to it. +func newReadTestClient(t *testing.T, results map[string]any, faults map[string]rpcFault) *Client { + t.Helper() + + // every read is gated on the chain tip; default to a comfortably deep chain + // unless the test overrides eth_blockNumber + if results != nil { + if _, ok := results["eth_blockNumber"]; !ok { + if _, ok := faults["eth_blockNumber"]; !ok { + results["eth_blockNumber"] = "0x1000" + } + } + } + + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + var req struct { + ID json.RawMessage `json:"id"` + Method string `json:"method"` + } + require.NoError(t, json.NewDecoder(r.Body).Decode(&req)) + + resp := map[string]any{"jsonrpc": "2.0", "id": json.RawMessage(req.ID)} + if fault, ok := faults[req.Method]; ok { + resp["error"] = map[string]any{"code": fault.code, "message": fault.message} + } else if result, ok := results[req.Method]; ok { + resp["result"] = result + } else { + t.Errorf("unexpected RPC method %s", req.Method) + resp["error"] = map[string]any{"code": -32601, "message": "method not found"} + } + require.NoError(t, json.NewEncoder(w).Encode(resp)) + })) + t.Cleanup(srv.Close) + + ethClient, err := ethclient.Dial(srv.URL) + require.NoError(t, err) + t.Cleanup(ethClient.Close) + + return &Client{ + logger: zerolog.Nop(), + rpcClient: &RPCClient{clients: []*ethclient.Client{ethClient}, logger: zerolog.Nop()}, + } +} + +func evmReadRequest(t *testing.T, queryType uint8, blockNumber uint64, payload []byte) *ucallbacktypes.ReadRequest { + t.Helper() + return &ucallbacktypes.ReadRequest{ + RequestId: "0xreq1", + DestinationChain: "eip155:11155111", + Query: packEvmEnvelope(t, queryType, 0, blockNumber, payload), + MinConfirmations: 1, + DestinationBlockHeight: 100, + } +} + +func TestExecuteRead_AccountBalance(t *testing.T) { + target := ethcommon.HexToAddress("0x1111111111111111111111111111111111111111") + payload, err := addressArgs.Pack(target) + require.NoError(t, err) + + client := newReadTestClient(t, map[string]any{ + "eth_getBlockByNumber": fakeHeader(100), + "eth_getBalance": "0xf4240", // 1_000_000 + }, nil) + + result, err := client.ExecuteRead(context.Background(), evmReadRequest(t, uint8(evmQueryAccountBalance), 0, payload)) + require.NoError(t, err) + assert.Equal(t, ucallbacktypes.ReadStatus_READ_STATUS_SUCCESS, result.Status) + assert.Equal(t, big.NewInt(1_000_000), new(big.Int).SetBytes(result.ResultData)) +} + +func TestExecuteRead_ContractCall(t *testing.T) { + target := ethcommon.HexToAddress("0x2222222222222222222222222222222222222222") + payload, err := addressBytesArgs.Pack(target, []byte{0xde, 0xad}) + require.NoError(t, err) + + t.Run("returns raw returndata", func(t *testing.T) { + client := newReadTestClient(t, map[string]any{ + "eth_getBlockByNumber": fakeHeader(100), + "eth_call": "0xcafebabe", + }, nil) + + result, err := client.ExecuteRead(context.Background(), evmReadRequest(t, uint8(evmQueryContractCall), 0, payload)) + require.NoError(t, err) + assert.Equal(t, ucallbacktypes.ReadStatus_READ_STATUS_SUCCESS, result.Status) + assert.Equal(t, []byte{0xca, 0xfe, 0xba, 0xbe}, result.ResultData) + }) + + t.Run("revert is a votable ERROR observation", func(t *testing.T) { + client := newReadTestClient(t, map[string]any{ + "eth_getBlockByNumber": fakeHeader(100), + }, map[string]rpcFault{ + "eth_call": {code: 3, message: "execution reverted"}, + }) + + result, err := client.ExecuteRead(context.Background(), evmReadRequest(t, uint8(evmQueryContractCall), 0, payload)) + require.NoError(t, err) + assert.Equal(t, ucallbacktypes.ReadStatus_READ_STATUS_ERROR, result.Status) + assert.Equal(t, ucallbacktypes.ReadErrorCode_READ_ERROR_REVERTED, result.ErrorCode) + assert.Empty(t, result.ResultData) + }) + + t.Run("non-revert rpc error is transient, not voted", func(t *testing.T) { + // a pruned/unsynced node (missing trie node) is node-specific, not a + // deterministic revert; it must retry, never produce an ERROR vote + client := newReadTestClient(t, map[string]any{ + "eth_getBlockByNumber": fakeHeader(100), + }, map[string]rpcFault{ + "eth_call": {code: -32000, message: "missing trie node"}, + }) + + result, err := client.ExecuteRead(context.Background(), evmReadRequest(t, uint8(evmQueryContractCall), 0, payload)) + require.Error(t, err) + assert.Nil(t, result) + }) +} + +func TestExecuteRead_StorageSlot(t *testing.T) { + target := ethcommon.HexToAddress("0x2222222222222222222222222222222222222222") + payload, err := addressBytes32Args.Pack(target, [32]byte{0x01}) + require.NoError(t, err) + + client := newReadTestClient(t, map[string]any{ + "eth_getBlockByNumber": fakeHeader(100), + "eth_getStorageAt": "0x" + fmt.Sprintf("%064x", 7), + }, nil) + + result, err := client.ExecuteRead(context.Background(), evmReadRequest(t, uint8(evmQueryStorageSlot), 0, payload)) + require.NoError(t, err) + assert.Equal(t, ucallbacktypes.ReadStatus_READ_STATUS_SUCCESS, result.Status) + require.Len(t, result.ResultData, 32) + assert.Equal(t, big.NewInt(7), new(big.Int).SetBytes(result.ResultData)) +} + +func TestExecuteRead_InvalidEnvelope(t *testing.T) { + client := newReadTestClient(t, nil, nil) + + result, err := client.ExecuteRead(context.Background(), &ucallbacktypes.ReadRequest{ + RequestId: "0xreq1", + Query: []byte{0x01, 0x02}, + DestinationBlockHeight: 100, + }) + require.NoError(t, err) + assert.Equal(t, ucallbacktypes.ReadStatus_READ_STATUS_ERROR, result.Status) + assert.Equal(t, ucallbacktypes.ReadErrorCode_READ_ERROR_INVALID_QUERY, result.ErrorCode) +} + +func TestExecuteRead_RPCFailureIsTransient(t *testing.T) { + target := ethcommon.HexToAddress("0x1111111111111111111111111111111111111111") + payload, err := addressArgs.Pack(target) + require.NoError(t, err) + + client := newReadTestClient(t, map[string]any{}, map[string]rpcFault{ + "eth_getBalance": {code: -32000, message: "node is syncing"}, + }) + + result, err := client.ExecuteRead(context.Background(), evmReadRequest(t, uint8(evmQueryAccountBalance), 0, payload)) + require.Error(t, err) + assert.Nil(t, result) +} + +func TestExecuteRead_PrunedStateIsTransient(t *testing.T) { + // A pruned node can serve the header but not old state. This is node-specific, + // not deterministic (an archive node returns the real value), so it must + // retry/abstain, never produce an ERROR vote — otherwise a pruned majority + // could wrongly quorum an ERROR for an address that has a balance. + t.Run("account balance", func(t *testing.T) { + target := ethcommon.HexToAddress("0x1111111111111111111111111111111111111111") + payload, err := addressArgs.Pack(target) + require.NoError(t, err) + + client := newReadTestClient(t, map[string]any{ + "eth_getBlockByNumber": fakeHeader(100), + }, map[string]rpcFault{ + "eth_getBalance": {code: -32000, message: "missing trie node"}, + }) + + result, err := client.ExecuteRead(context.Background(), evmReadRequest(t, uint8(evmQueryAccountBalance), 0, payload)) + require.Error(t, err) + assert.Nil(t, result) + }) + + t.Run("storage slot", func(t *testing.T) { + target := ethcommon.HexToAddress("0x2222222222222222222222222222222222222222") + payload, err := addressBytes32Args.Pack(target, [32]byte{0x01}) + require.NoError(t, err) + + client := newReadTestClient(t, map[string]any{ + "eth_getBlockByNumber": fakeHeader(100), + }, map[string]rpcFault{ + "eth_getStorageAt": {code: -32000, message: "missing trie node"}, + }) + + result, err := client.ExecuteRead(context.Background(), evmReadRequest(t, uint8(evmQueryStorageSlot), 0, payload)) + require.Error(t, err) + assert.Nil(t, result) + }) +} + +func TestExecuteRead_EnvelopeBlockNumberUsedWhenNotPinned(t *testing.T) { + target := ethcommon.HexToAddress("0x1111111111111111111111111111111111111111") + payload, err := addressArgs.Pack(target) + require.NoError(t, err) + + client := newReadTestClient(t, map[string]any{ + "eth_getBlockByNumber": fakeHeader(55), + "eth_getBalance": "0x1", + }, nil) + + req := evmReadRequest(t, uint8(evmQueryAccountBalance), 55, payload) + req.DestinationBlockHeight = 0 // client-provided height in the envelope + + result, err := client.ExecuteRead(context.Background(), req) + require.NoError(t, err) + assert.Equal(t, ucallbacktypes.ReadStatus_READ_STATUS_SUCCESS, result.Status) +} + +func TestExecuteRead_MissingHeightIsVotableError(t *testing.T) { + target := ethcommon.HexToAddress("0x1111111111111111111111111111111111111111") + payload, err := addressArgs.Pack(target) + require.NoError(t, err) + + client := newReadTestClient(t, nil, nil) + + req := evmReadRequest(t, uint8(evmQueryAccountBalance), 0, payload) + req.DestinationBlockHeight = 0 + + result, err := client.ExecuteRead(context.Background(), req) + require.NoError(t, err) + assert.Equal(t, ucallbacktypes.ReadStatus_READ_STATUS_ERROR, result.Status) +} + +func TestExecuteRead_ConfirmationGate(t *testing.T) { + target := ethcommon.HexToAddress("0x1111111111111111111111111111111111111111") + payload, err := addressArgs.Pack(target) + require.NoError(t, err) + + t.Run("height not deep enough is transient", func(t *testing.T) { + client := newReadTestClient(t, map[string]any{ + "eth_blockNumber": "0x64", // 100 + }, nil) + + req := evmReadRequest(t, uint8(evmQueryAccountBalance), 0, payload) + req.DestinationBlockHeight = 100 + req.MinConfirmations = 5 // needs chain at >= 105 + + result, err := client.ExecuteRead(context.Background(), req) + require.Error(t, err) + assert.Nil(t, result) + }) + + t.Run("executes once deep enough", func(t *testing.T) { + client := newReadTestClient(t, map[string]any{ + "eth_blockNumber": "0x69", // 105 + "eth_getBlockByNumber": fakeHeader(100), + "eth_getBalance": "0x1", + }, nil) + + req := evmReadRequest(t, uint8(evmQueryAccountBalance), 0, payload) + req.DestinationBlockHeight = 100 + req.MinConfirmations = 5 + + result, err := client.ExecuteRead(context.Background(), req) + require.NoError(t, err) + assert.Equal(t, ucallbacktypes.ReadStatus_READ_STATUS_SUCCESS, result.Status) + }) +} diff --git a/universalClient/externalchains/evm/rpc_client.go b/universalClient/externalchains/evm/rpc_client.go index b8c83d04..433a8ef3 100644 --- a/universalClient/externalchains/evm/rpc_client.go +++ b/universalClient/externalchains/evm/rpc_client.go @@ -182,6 +182,45 @@ func (rc *RPCClient) GetBalance(ctx context.Context, address ethcommon.Address) return balance, err } +// GetBalanceAt fetches the native token balance for an address at a specific block. +func (rc *RPCClient) GetBalanceAt(ctx context.Context, address ethcommon.Address, blockNumber *big.Int) (*big.Int, error) { + var balance *big.Int + err := rc.executeWithFailover(ctx, "get_balance_at", func(client *ethclient.Client) error { + callCtx, cancel := context.WithTimeout(ctx, 10*time.Second) + defer cancel() + var innerErr error + balance, innerErr = client.BalanceAt(callCtx, address, blockNumber) + return innerErr + }) + return balance, err +} + +// GetStorageAt fetches a storage slot value for a contract at a specific block. +func (rc *RPCClient) GetStorageAt(ctx context.Context, address ethcommon.Address, slot ethcommon.Hash, blockNumber *big.Int) ([]byte, error) { + var value []byte + err := rc.executeWithFailover(ctx, "get_storage_at", func(client *ethclient.Client) error { + callCtx, cancel := context.WithTimeout(ctx, 10*time.Second) + defer cancel() + var innerErr error + value, innerErr = client.StorageAt(callCtx, address, slot, blockNumber) + return innerErr + }) + return value, err +} + +// GetHeaderByNumber fetches a block header by number. +func (rc *RPCClient) GetHeaderByNumber(ctx context.Context, blockNumber *big.Int) (*types.Header, error) { + var header *types.Header + err := rc.executeWithFailover(ctx, "get_header_by_number", func(client *ethclient.Client) error { + callCtx, cancel := context.WithTimeout(ctx, 10*time.Second) + defer cancel() + var innerErr error + header, innerErr = client.HeaderByNumber(callCtx, blockNumber) + return innerErr + }) + return header, err +} + // FilterLogs fetches logs matching the filter query func (rc *RPCClient) FilterLogs(ctx context.Context, query ethereum.FilterQuery) ([]types.Log, error) { var logs []types.Log diff --git a/universalClient/externalchains/svm/client.go b/universalClient/externalchains/svm/client.go index bdafd098..e0afd3a0 100644 --- a/universalClient/externalchains/svm/client.go +++ b/universalClient/externalchains/svm/client.go @@ -12,6 +12,7 @@ import ( "github.com/pushchain/push-chain-node/universalClient/db" "github.com/pushchain/push-chain-node/universalClient/externalchains/common" "github.com/pushchain/push-chain-node/universalClient/pushsigner" + "github.com/pushchain/push-chain-node/universalClient/store" uregistrytypes "github.com/pushchain/push-chain-node/x/uregistry/types" ) @@ -96,16 +97,14 @@ func NewClient( // Initialize components that don't require RPC client if pushSigner != nil { - inboundEnabled := config.Enabled != nil && config.Enabled.IsInboundEnabled - outboundEnabled := config.Enabled != nil && config.Enabled.IsOutboundEnabled - client.eventProcessor = common.NewEventProcessor( - pushSigner, - database, - chainIDStr, - inboundEnabled, - outboundEnabled, - log, - ) + ep := common.NewEventProcessor(database, chainIDStr, log) + if config.Enabled != nil && config.Enabled.IsInboundEnabled { + ep.RegisterHandler(store.EventTypeInbound, common.NewInboundObservationEventProcessor(pushSigner, database, log)) + } + if config.Enabled != nil && config.Enabled.IsOutboundEnabled { + ep.RegisterHandler(store.EventTypeOutbound, common.NewOutboundObservationEventProcessor(pushSigner, database, log)) + } + client.eventProcessor = ep } return client, nil @@ -209,6 +208,14 @@ func (c *Client) GetTxBuilder() (common.TxBuilder, error) { return c.txBuilder, nil } +// GetReadRequestHandler returns the read request handler for this chain +func (c *Client) GetReadRequestHandler() (common.ReadRequestHandler, error) { + if c.rpcClient == nil { + return nil, fmt.Errorf("read handler not available for chain %s (client not started)", c.chainIDStr) + } + return c, nil +} + // initializeComponents creates all components that require the RPC client func (c *Client) initializeComponents() error { // Create event listener if gateway is configured diff --git a/universalClient/externalchains/svm/event_parser.go b/universalClient/externalchains/svm/event_parser.go index 68f1dd4d..cc65ea4c 100644 --- a/universalClient/externalchains/svm/event_parser.go +++ b/universalClient/externalchains/svm/event_parser.go @@ -177,7 +177,7 @@ func parseOutboundObservationEvent(log string, signature string, slot uint64, lo } // Create OutboundEvent payload - payload := common.OutboundEvent{ + payload := common.OutboundObservation{ TxID: txID, UniversalTxID: universalTxID, GasFeeUsed: fmt.Sprintf("%d", gasUsed), @@ -250,7 +250,7 @@ func parseUniversalTxEvent(event *store.Event, decoded []byte, logIndex uint, ch } // decodeUniversalTxEvent decodes a TxWithFunds event -func decodeUniversalTxEvent(data []byte, logger zerolog.Logger) (*common.UniversalTx, error) { +func decodeUniversalTxEvent(data []byte, logger zerolog.Logger) (*common.InboundObservation, error) { if len(data) < 120 { logger.Warn(). Int("data_len", len(data)). @@ -258,7 +258,7 @@ func decodeUniversalTxEvent(data []byte, logger zerolog.Logger) (*common.Univers } offset := 8 - payload := &common.UniversalTx{} + payload := &common.InboundObservation{} // Parse sender (32 bytes) if len(data) < offset+32 { diff --git a/universalClient/externalchains/svm/event_parser_test.go b/universalClient/externalchains/svm/event_parser_test.go index 88ae4436..f7c6f060 100644 --- a/universalClient/externalchains/svm/event_parser_test.go +++ b/universalClient/externalchains/svm/event_parser_test.go @@ -307,7 +307,7 @@ func TestParseSendFundsEvent(t *testing.T) { assert.Equal(t, store.ConfirmationFast, event.ConfirmationType) // Unmarshal EventData - var utx common.UniversalTx + var utx common.InboundObservation require.NoError(t, json.Unmarshal(event.EventData, &utx)) assert.Equal(t, chainID, utx.SourceChain) @@ -344,7 +344,7 @@ func TestParseSendFundsEvent(t *testing.T) { data := buildSendFundsPayload(s, r, tok, 0, nil, rev, 0, nil, false) event := ParseEvent(wrapAsLog(data), sig, 1, 0, EventTypeSendFunds, chainID, logger) require.NotNil(t, event) - var utx common.UniversalTx + var utx common.InboundObservation require.NoError(t, json.Unmarshal(event.EventData, &utx)) assert.False(t, utx.FromCEA) }) @@ -355,7 +355,7 @@ func TestParseSendFundsEvent(t *testing.T) { data := buildSendFundsPayload(s, r, tok, 0, nil, rev, 0, nil, false) event := ParseEvent(wrapAsLog(data), sig, 1, 0, EventTypeSendFunds, chainID, logger) require.NotNil(t, event) - var utx common.UniversalTx + var utx common.InboundObservation require.NoError(t, json.Unmarshal(event.EventData, &utx)) assert.Empty(t, utx.RawPayload) assert.Empty(t, utx.VerificationData) @@ -368,7 +368,7 @@ func TestParseSendFundsEvent(t *testing.T) { data := buildSendFundsPayload(s, r, tok, maxU64, nil, rev, 0, nil, false) event := ParseEvent(wrapAsLog(data), sig, 1, 0, EventTypeSendFunds, chainID, logger) require.NotNil(t, event) - var utx common.UniversalTx + var utx common.InboundObservation require.NoError(t, json.Unmarshal(event.EventData, &utx)) assert.Equal(t, "18446744073709551615", utx.Amount) }) @@ -423,7 +423,7 @@ func TestParseOutboundObservationEvent(t *testing.T) { assert.Equal(t, store.StatusPending, event.Status) assert.Equal(t, store.ConfirmationStandard, event.ConfirmationType) - var outbound common.OutboundEvent + var outbound common.OutboundObservation require.NoError(t, json.Unmarshal(event.EventData, &outbound)) assert.Equal(t, "0x"+hex.EncodeToString(txID[:]), outbound.TxID) assert.Equal(t, "0x"+hex.EncodeToString(utxID[:]), outbound.UniversalTxID) @@ -439,7 +439,7 @@ func TestParseOutboundObservationEvent(t *testing.T) { event := ParseEvent(wrapAsLog(data), signature, 1, 0, EventTypeFinalizeUniversalTx, chainID, logger) require.NotNil(t, event) - var outbound common.OutboundEvent + var outbound common.OutboundObservation require.NoError(t, json.Unmarshal(event.EventData, &outbound)) assert.Equal(t, solana.PublicKeyFromBytes(token[:]).String(), outbound.Pc20WrapperAddress) }) @@ -450,7 +450,7 @@ func TestParseOutboundObservationEvent(t *testing.T) { event := ParseEvent(wrapAsLog(data), signature, 1, 0, EventTypeFinalizeUniversalTx, chainID, logger) require.NotNil(t, event) - var outbound common.OutboundEvent + var outbound common.OutboundObservation require.NoError(t, json.Unmarshal(event.EventData, &outbound)) assert.Empty(t, outbound.Pc20WrapperAddress) }) @@ -461,7 +461,7 @@ func TestParseOutboundObservationEvent(t *testing.T) { event := ParseEvent(wrapAsLog(data), signature, 1, 0, EventTypeRevertUniversalTx, chainID, logger) require.NotNil(t, event) - var outbound common.OutboundEvent + var outbound common.OutboundObservation require.NoError(t, json.Unmarshal(event.EventData, &outbound)) assert.Empty(t, outbound.Pc20WrapperAddress) assert.Equal(t, "7777", outbound.GasFeeUsed) @@ -473,7 +473,7 @@ func TestParseOutboundObservationEvent(t *testing.T) { event := ParseEvent(wrapAsLog(data), signature, 1, 0, EventTypeFundsRescued, chainID, logger) require.NotNil(t, event) - var outbound common.OutboundEvent + var outbound common.OutboundObservation require.NoError(t, json.Unmarshal(event.EventData, &outbound)) assert.Empty(t, outbound.Pc20WrapperAddress) assert.Equal(t, "3333", outbound.GasFeeUsed) @@ -514,7 +514,7 @@ func TestParseOutboundObservationEvent(t *testing.T) { event := ParseEvent(wrapAsLog(data), signature, 100, 0, EventTypeFinalizeUniversalTx, chainID, logger) require.NotNil(t, event) - var outbound common.OutboundEvent + var outbound common.OutboundObservation require.NoError(t, json.Unmarshal(event.EventData, &outbound)) assert.Contains(t, outbound.TxID, "0x1111") assert.Contains(t, outbound.UniversalTxID, "0x2222") @@ -536,7 +536,7 @@ func TestParseOutboundObservationEvent(t *testing.T) { event := ParseEvent(wrapAsLog(data), signature, 100, 0, EventTypeFinalizeUniversalTx, chainID, logger) require.NotNil(t, event) - var outbound common.OutboundEvent + var outbound common.OutboundObservation require.NoError(t, json.Unmarshal(event.EventData, &outbound)) assert.Equal(t, "0x"+hex.EncodeToString(txID[:]), outbound.TxID) assert.Equal(t, "0x"+hex.EncodeToString(utxID[:]), outbound.UniversalTxID) @@ -549,7 +549,7 @@ func TestParseOutboundObservationEvent(t *testing.T) { event := ParseEvent(wrapAsLog(data), signature, 100, 0, EventTypeFinalizeUniversalTx, chainID, logger) require.NotNil(t, event) - var outbound common.OutboundEvent + var outbound common.OutboundObservation require.NoError(t, json.Unmarshal(event.EventData, &outbound)) assert.Equal(t, "0", outbound.GasFeeUsed) }) @@ -560,7 +560,7 @@ func TestParseOutboundObservationEvent(t *testing.T) { event := ParseEvent(wrapAsLog(data), signature, 100, 0, EventTypeFinalizeUniversalTx, chainID, logger) require.NotNil(t, event) - var outbound common.OutboundEvent + var outbound common.OutboundObservation require.NoError(t, json.Unmarshal(event.EventData, &outbound)) assert.Equal(t, "18446744073709551615", outbound.GasFeeUsed) }) diff --git a/universalClient/externalchains/svm/read_envelope.go b/universalClient/externalchains/svm/read_envelope.go new file mode 100644 index 00000000..b32d172b --- /dev/null +++ b/universalClient/externalchains/svm/read_envelope.go @@ -0,0 +1,66 @@ +package svm + +import ( + "fmt" + + "github.com/ethereum/go-ethereum/accounts/abi" +) + +// solanaQueryType mirrors the SolanaQueryEnvelope enum from the read spec. +type solanaQueryType uint8 + +const ( + solanaQueryLamportBalance solanaQueryType = 0 + solanaQuerySPLTokenAccount solanaQueryType = 1 + solanaQueryRawAccountData solanaQueryType = 2 +) + +// solanaQueryEnvelope is the decoded abi.encode(SolanaQueryEnvelope) query — +// ABI-encoded because it is built by UniversalCallback.sol on Push EVM. +// The target account pubkey travels in ReadSpec.account.owner (32 bytes), not here. +type solanaQueryEnvelope struct { + QueryType solanaQueryType + MinSlot uint64 + Payload []byte // empty for all v1 query types +} + +var svmEnvelopeArgs = func() abi.Arguments { + tupleTy, err := abi.NewType("tuple", "", []abi.ArgumentMarshaling{ + {Name: "queryType", Type: "uint8"}, + {Name: "slotRef", Type: "tuple", Components: []abi.ArgumentMarshaling{ + {Name: "minSlot", Type: "uint64"}, + }}, + {Name: "payload", Type: "bytes"}, + }) + if err != nil { + panic(fmt.Sprintf("svm: invalid envelope abi type: %v", err)) + } + return abi.Arguments{{Name: "envelope", Type: tupleTy}} +}() + +type rawSvmEnvelope struct { + QueryType uint8 + SlotRef struct { + MinSlot uint64 + } + Payload []byte +} + +// decodeSolanaQueryEnvelope decodes ReadSpec.query for solana chains. +func decodeSolanaQueryEnvelope(query []byte) (*solanaQueryEnvelope, error) { + vals, err := svmEnvelopeArgs.Unpack(query) + if err != nil { + return nil, fmt.Errorf("failed to unpack SolanaQueryEnvelope: %w", err) + } + raw := *abi.ConvertType(vals[0], new(rawSvmEnvelope)).(*rawSvmEnvelope) + + env := &solanaQueryEnvelope{ + QueryType: solanaQueryType(raw.QueryType), + MinSlot: raw.SlotRef.MinSlot, + Payload: raw.Payload, + } + if env.QueryType > solanaQueryRawAccountData { + return nil, fmt.Errorf("unknown SolanaQueryType %d", env.QueryType) + } + return env, nil +} diff --git a/universalClient/externalchains/svm/read_envelope_test.go b/universalClient/externalchains/svm/read_envelope_test.go new file mode 100644 index 00000000..d5103053 --- /dev/null +++ b/universalClient/externalchains/svm/read_envelope_test.go @@ -0,0 +1,34 @@ +package svm + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestDecodeSolanaQueryEnvelope(t *testing.T) { + data, err := svmEnvelopeArgs.Pack(rawSvmEnvelope{ + QueryType: uint8(solanaQuerySPLTokenAccount), + SlotRef: struct { + MinSlot uint64 + }{42}, + Payload: nil, + }) + require.NoError(t, err) + + env, err := decodeSolanaQueryEnvelope(data) + require.NoError(t, err) + assert.Equal(t, solanaQuerySPLTokenAccount, env.QueryType) + assert.Equal(t, uint64(42), env.MinSlot) + assert.Empty(t, env.Payload) + + _, err = decodeSolanaQueryEnvelope([]byte{0x00}) + assert.Error(t, err) + + // unknown query type + bad, err := svmEnvelopeArgs.Pack(rawSvmEnvelope{QueryType: 9}) + require.NoError(t, err) + _, err = decodeSolanaQueryEnvelope(bad) + assert.Error(t, err) +} diff --git a/universalClient/externalchains/svm/read_executor.go b/universalClient/externalchains/svm/read_executor.go new file mode 100644 index 00000000..65d87173 --- /dev/null +++ b/universalClient/externalchains/svm/read_executor.go @@ -0,0 +1,94 @@ +package svm + +import ( + "context" + "encoding/binary" + "fmt" + "math/big" + + "github.com/gagliardetto/solana-go" + + "github.com/pushchain/push-chain-node/universalClient/externalchains/common" + ucallbacktypes "github.com/pushchain/push-chain-node/x/ucallback/types" +) + +// splTokenAmountOffset is the byte offset of the u64 amount in an SPL token account. +const splTokenAmountOffset = 64 + +// ExecuteRead implements common.ChainReader for Solana chains. +// +// Solana cannot query state at an exact past slot, so reads run at finalized +// commitment with minContextSlot as a staleness floor. The observed slot is not +// carried on the result or the ballot; the vote covers the result value only. +func (c *Client) ExecuteRead(ctx context.Context, req *ucallbacktypes.ReadRequest) (*ucallbacktypes.ReadResult, error) { + env, err := decodeSolanaQueryEnvelope(req.Query) + if err != nil { + return common.NewReadErrorResult(ucallbacktypes.ReadErrorCode_READ_ERROR_INVALID_QUERY), nil + } + + if len(req.Owner) != solana.PublicKeyLength { + return common.NewReadErrorResult(ucallbacktypes.ReadErrorCode_READ_ERROR_INVALID_QUERY), nil + } + account := solana.PublicKeyFromBytes(req.Owner) + + minSlot := max(env.MinSlot, req.DestinationBlockHeight) + + switch env.QueryType { + case solanaQueryLamportBalance: + balance, slot, rpcErr := c.rpcClient.GetBalanceWithSlot(ctx, account) + if rpcErr != nil { + return nil, rpcErr + } + if slot < minSlot { + return nil, fmt.Errorf("observed slot %d below min slot %d", slot, minSlot) + } + resultData, encErr := common.EncodeUint256Result(new(big.Int).SetUint64(balance)) + if encErr != nil { + return common.NewReadErrorResult(ucallbacktypes.ReadErrorCode_READ_ERROR_INVALID_RESULT), nil + } + return &ucallbacktypes.ReadResult{ + Status: ucallbacktypes.ReadStatus_READ_STATUS_SUCCESS, + ResultData: resultData, + }, nil + + case solanaQuerySPLTokenAccount: + data, owner, found, _, rpcErr := c.rpcClient.GetAccountInfoWithSlot(ctx, account, minSlot) + if rpcErr != nil { + return nil, rpcErr + } + if !found { + return common.NewReadErrorResult(ucallbacktypes.ReadErrorCode_READ_ERROR_NOT_FOUND), nil + } + if !owner.Equals(solana.TokenProgramID) && !owner.Equals(solana.Token2022ProgramID) { + return common.NewReadErrorResult(ucallbacktypes.ReadErrorCode_READ_ERROR_INVALID_RESULT), nil + } + if len(data) < splTokenAmountOffset+8 { + return common.NewReadErrorResult(ucallbacktypes.ReadErrorCode_READ_ERROR_INVALID_RESULT), nil + } + amount := binary.LittleEndian.Uint64(data[splTokenAmountOffset : splTokenAmountOffset+8]) + resultData, encErr := common.EncodeUint256Result(new(big.Int).SetUint64(amount)) + if encErr != nil { + return common.NewReadErrorResult(ucallbacktypes.ReadErrorCode_READ_ERROR_INVALID_RESULT), nil + } + return &ucallbacktypes.ReadResult{ + Status: ucallbacktypes.ReadStatus_READ_STATUS_SUCCESS, + ResultData: resultData, + }, nil + + case solanaQueryRawAccountData: + data, _, found, _, rpcErr := c.rpcClient.GetAccountInfoWithSlot(ctx, account, minSlot) + if rpcErr != nil { + return nil, rpcErr + } + if !found { + return common.NewReadErrorResult(ucallbacktypes.ReadErrorCode_READ_ERROR_NOT_FOUND), nil + } + return &ucallbacktypes.ReadResult{ + Status: ucallbacktypes.ReadStatus_READ_STATUS_SUCCESS, + ResultData: data, + }, nil + + default: + return common.NewReadErrorResult(ucallbacktypes.ReadErrorCode_READ_ERROR_INVALID_QUERY), nil + } +} diff --git a/universalClient/externalchains/svm/read_executor_test.go b/universalClient/externalchains/svm/read_executor_test.go new file mode 100644 index 00000000..605a3c7b --- /dev/null +++ b/universalClient/externalchains/svm/read_executor_test.go @@ -0,0 +1,210 @@ +package svm + +import ( + "context" + "encoding/base64" + "encoding/binary" + "encoding/json" + "math/big" + "net/http" + "net/http/httptest" + "testing" + + "github.com/gagliardetto/solana-go" + solrpc "github.com/gagliardetto/solana-go/rpc" + "github.com/rs/zerolog" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + ucallbacktypes "github.com/pushchain/push-chain-node/x/ucallback/types" +) + +// accountInfoResult builds a getAccountInfo result with base64 data. +func accountInfoResult(slot uint64, owner solana.PublicKey, data []byte) map[string]any { + return map[string]any{ + "context": map[string]any{"slot": slot}, + "value": map[string]any{ + "data": []any{base64.StdEncoding.EncodeToString(data), "base64"}, + "executable": false, + "lamports": 1, + "owner": owner.String(), + "rentEpoch": 0, + }, + } +} + +// newReadTestClient spins up a JSON-RPC server answering from results keyed by +// method name, and returns a Client wired to it. +func newReadTestClient(t *testing.T, results map[string]any) *Client { + t.Helper() + + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + var req struct { + ID json.RawMessage `json:"id"` + Method string `json:"method"` + } + require.NoError(t, json.NewDecoder(r.Body).Decode(&req)) + + resp := map[string]any{"jsonrpc": "2.0", "id": json.RawMessage(req.ID)} + if result, ok := results[req.Method]; ok { + resp["result"] = result + } else { + t.Errorf("unexpected RPC method %s", req.Method) + resp["error"] = map[string]any{"code": -32601, "message": "method not found"} + } + require.NoError(t, json.NewEncoder(w).Encode(resp)) + })) + t.Cleanup(srv.Close) + + return &Client{ + logger: zerolog.Nop(), + rpcClient: &RPCClient{clients: []*solrpc.Client{solrpc.New(srv.URL)}, logger: zerolog.Nop()}, + } +} + +func svmReadRequest(t *testing.T, queryType uint8, minSlot uint64, owner []byte) *ucallbacktypes.ReadRequest { + t.Helper() + query, err := svmEnvelopeArgs.Pack(rawSvmEnvelope{ + QueryType: queryType, + SlotRef: struct { + MinSlot uint64 + }{minSlot}, + }) + require.NoError(t, err) + return &ucallbacktypes.ReadRequest{ + RequestId: "0xreq1", + DestinationChain: "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + Owner: owner, + Query: query, + } +} + +func testAccount() solana.PublicKey { + return solana.MustPublicKeyFromBase58("So11111111111111111111111111111111111111112") +} + +func TestExecuteRead_LamportBalance(t *testing.T) { + account := testAccount() + + t.Run("success", func(t *testing.T) { + client := newReadTestClient(t, map[string]any{ + "getBalance": map[string]any{ + "context": map[string]any{"slot": 900}, + "value": 5_000_000, + }, + }) + + result, err := client.ExecuteRead(context.Background(), svmReadRequest(t, uint8(solanaQueryLamportBalance), 800, account.Bytes())) + require.NoError(t, err) + assert.Equal(t, ucallbacktypes.ReadStatus_READ_STATUS_SUCCESS, result.Status) + assert.Equal(t, big.NewInt(5_000_000), new(big.Int).SetBytes(result.ResultData)) + }) + + t.Run("observed slot below min slot is transient", func(t *testing.T) { + client := newReadTestClient(t, map[string]any{ + "getBalance": map[string]any{ + "context": map[string]any{"slot": 700}, + "value": 5_000_000, + }, + }) + + result, err := client.ExecuteRead(context.Background(), svmReadRequest(t, uint8(solanaQueryLamportBalance), 800, account.Bytes())) + require.Error(t, err) + assert.Nil(t, result) + }) +} + +func TestExecuteRead_SPLTokenAccount(t *testing.T) { + account := testAccount() + + tokenAccountData := func(amount uint64) []byte { + data := make([]byte, 165) + binary.LittleEndian.PutUint64(data[splTokenAmountOffset:], amount) + return data + } + + t.Run("success", func(t *testing.T) { + client := newReadTestClient(t, map[string]any{ + "getAccountInfo": accountInfoResult(900, solana.TokenProgramID, tokenAccountData(777)), + }) + + result, err := client.ExecuteRead(context.Background(), svmReadRequest(t, uint8(solanaQuerySPLTokenAccount), 800, account.Bytes())) + require.NoError(t, err) + assert.Equal(t, ucallbacktypes.ReadStatus_READ_STATUS_SUCCESS, result.Status) + assert.Equal(t, big.NewInt(777), new(big.Int).SetBytes(result.ResultData)) + }) + + t.Run("non token-program owner is a votable ERROR", func(t *testing.T) { + client := newReadTestClient(t, map[string]any{ + "getAccountInfo": accountInfoResult(900, solana.SystemProgramID, tokenAccountData(777)), + }) + + result, err := client.ExecuteRead(context.Background(), svmReadRequest(t, uint8(solanaQuerySPLTokenAccount), 0, account.Bytes())) + require.NoError(t, err) + assert.Equal(t, ucallbacktypes.ReadStatus_READ_STATUS_ERROR, result.Status) + assert.Equal(t, ucallbacktypes.ReadErrorCode_READ_ERROR_INVALID_RESULT, result.ErrorCode) + }) + + t.Run("truncated account data is a votable ERROR", func(t *testing.T) { + client := newReadTestClient(t, map[string]any{ + "getAccountInfo": accountInfoResult(900, solana.TokenProgramID, make([]byte, 10)), + }) + + result, err := client.ExecuteRead(context.Background(), svmReadRequest(t, uint8(solanaQuerySPLTokenAccount), 0, account.Bytes())) + require.NoError(t, err) + assert.Equal(t, ucallbacktypes.ReadStatus_READ_STATUS_ERROR, result.Status) + assert.Equal(t, ucallbacktypes.ReadErrorCode_READ_ERROR_INVALID_RESULT, result.ErrorCode) + }) + + t.Run("missing account is a votable ERROR", func(t *testing.T) { + client := newReadTestClient(t, map[string]any{ + "getAccountInfo": map[string]any{ + "context": map[string]any{"slot": 900}, + "value": nil, + }, + }) + + result, err := client.ExecuteRead(context.Background(), svmReadRequest(t, uint8(solanaQuerySPLTokenAccount), 0, account.Bytes())) + require.NoError(t, err) + assert.Equal(t, ucallbacktypes.ReadStatus_READ_STATUS_ERROR, result.Status) + assert.Equal(t, ucallbacktypes.ReadErrorCode_READ_ERROR_NOT_FOUND, result.ErrorCode) + }) +} + +func TestExecuteRead_RawAccountData(t *testing.T) { + account := testAccount() + raw := []byte{0x01, 0x02, 0x03} + + client := newReadTestClient(t, map[string]any{ + "getAccountInfo": accountInfoResult(900, solana.SystemProgramID, raw), + }) + + result, err := client.ExecuteRead(context.Background(), svmReadRequest(t, uint8(solanaQueryRawAccountData), 0, account.Bytes())) + require.NoError(t, err) + assert.Equal(t, ucallbacktypes.ReadStatus_READ_STATUS_SUCCESS, result.Status) + assert.Equal(t, raw, result.ResultData) +} + +func TestExecuteRead_InvalidInputs(t *testing.T) { + account := testAccount() + + t.Run("invalid envelope is a votable ERROR", func(t *testing.T) { + client := newReadTestClient(t, nil) + + result, err := client.ExecuteRead(context.Background(), &ucallbacktypes.ReadRequest{ + RequestId: "0xreq1", + Owner: account.Bytes(), + Query: []byte{0x01}, + }) + require.NoError(t, err) + assert.Equal(t, ucallbacktypes.ReadStatus_READ_STATUS_ERROR, result.Status) + }) + + t.Run("owner not 32 bytes is a votable ERROR", func(t *testing.T) { + client := newReadTestClient(t, nil) + + result, err := client.ExecuteRead(context.Background(), svmReadRequest(t, uint8(solanaQueryLamportBalance), 0, []byte{0x01, 0x02})) + require.NoError(t, err) + assert.Equal(t, ucallbacktypes.ReadStatus_READ_STATUS_ERROR, result.Status) + }) +} diff --git a/universalClient/externalchains/svm/rpc_client.go b/universalClient/externalchains/svm/rpc_client.go index fb788b7a..ee1ac9a0 100644 --- a/universalClient/externalchains/svm/rpc_client.go +++ b/universalClient/externalchains/svm/rpc_client.go @@ -386,6 +386,53 @@ func (rc *RPCClient) GetAccountData(ctx context.Context, pubkey solana.PublicKey return accountData, err } +// GetBalanceWithSlot fetches the lamport balance for an account at finalized +// commitment, returning the context slot the value was observed at. +func (rc *RPCClient) GetBalanceWithSlot(ctx context.Context, pubkey solana.PublicKey) (uint64, uint64, error) { + var balance, slot uint64 + err := rc.executeWithFailover(ctx, "get_balance", func(client *rpc.Client) error { + resp, innerErr := client.GetBalance(ctx, pubkey, rpc.CommitmentFinalized) + if innerErr != nil { + return innerErr + } + balance = resp.Value + slot = resp.RPCContext.Context.Slot + return nil + }) + return balance, slot, err +} + +// GetAccountInfoWithSlot fetches account data at finalized commitment with an +// optional minimum context slot, returning the context slot it was observed at. +// found=false means the account does not exist (a valid, votable observation). +func (rc *RPCClient) GetAccountInfoWithSlot(ctx context.Context, pubkey solana.PublicKey, minContextSlot uint64) (data []byte, owner solana.PublicKey, found bool, slot uint64, err error) { + err = rc.executeWithFailover(ctx, "get_account_info", func(client *rpc.Client) error { + opts := &rpc.GetAccountInfoOpts{Commitment: rpc.CommitmentFinalized} + if minContextSlot > 0 { + opts.MinContextSlot = &minContextSlot + } + resp, innerErr := client.GetAccountInfoWithOpts(ctx, pubkey, opts) + if innerErr != nil { + if innerErr == rpc.ErrNotFound { + found = false + return nil + } + return innerErr + } + if resp.Value == nil { + found = false + slot = resp.RPCContext.Context.Slot + return nil + } + found = true + data = resp.Value.Data.GetBinary() + owner = resp.Value.Owner + slot = resp.RPCContext.Context.Slot + return nil + }) + return data, owner, found, slot, err +} + // Close closes all RPC connections func (rc *RPCClient) Close() { rc.mu.Lock() diff --git a/universalClient/externalchains/web2/read_envelope.go b/universalClient/externalchains/web2/read_envelope.go new file mode 100644 index 00000000..b56d1048 --- /dev/null +++ b/universalClient/externalchains/web2/read_envelope.go @@ -0,0 +1,140 @@ +package web2 + +import ( + "fmt" + + "github.com/ethereum/go-ethereum/accounts/abi" +) + +// web2Method mirrors the Web2QueryEnvelope method enum from the read spec. +type web2Method uint8 + +const ( + web2MethodGet web2Method = 0 + web2MethodPost web2Method = 1 +) + +// extractValueType mirrors the Web2Extract valueType enum. +type extractValueType uint8 + +const ( + valueTypeUint256 extractValueType = 0 + valueTypeInt256 extractValueType = 1 + valueTypeBool extractValueType = 2 + valueTypeString extractValueType = 3 + valueTypeBytes extractValueType = 4 +) + +// extractMode mirrors the Web2Extract mode enum. +type extractMode uint8 + +// modeIdentical is the only supported aggregation mode: quorum on identical +// result bytes. More modes (e.g. median) need core-side aggregation first. +const modeIdentical extractMode = 0 + +// web2Extract is one declared field to pull out of the JSON response. +type web2Extract struct { + Path string // JSONPath into the response, e.g. "$.data.price" + ValueType extractValueType + Mode extractMode + Decimals uint8 // numeric JSON scaled by 10^decimals before encoding +} + +// web2QueryEnvelope is the decoded abi.encode(Web2QueryEnvelope) query. +type web2QueryEnvelope struct { + Method web2Method + URL string + Headers []byte // canonical JSON object of header name -> value + Body []byte // POST only + TimeoutMs uint64 + Extract []web2Extract +} + +var web2EnvelopeArgs = mustReadArgs(abi.ArgumentMarshaling{Type: "tuple", Components: []abi.ArgumentMarshaling{ + {Name: "method", Type: "uint8"}, + {Name: "url", Type: "string"}, + {Name: "headers", Type: "bytes"}, + {Name: "body", Type: "bytes"}, + {Name: "timeoutMs", Type: "uint64"}, + {Name: "extract", Type: "tuple[]", Components: []abi.ArgumentMarshaling{ + {Name: "path", Type: "string"}, + {Name: "valueType", Type: "uint8"}, + {Name: "mode", Type: "uint8"}, + {Name: "decimals", Type: "uint8"}, + }}, +}}) + +func mustReadArgs(marshalings ...abi.ArgumentMarshaling) abi.Arguments { + args := make(abi.Arguments, 0, len(marshalings)) + for i, m := range marshalings { + if m.Name == "" { + m.Name = fmt.Sprintf("arg%d", i) + } + typ, err := abi.NewType(m.Type, "", m.Components) + if err != nil { + panic(fmt.Sprintf("web2: invalid abi type %q: %v", m.Type, err)) + } + args = append(args, abi.Argument{Name: m.Name, Type: typ}) + } + return args +} + +type rawWeb2Extract struct { + Path string + ValueType uint8 + Mode uint8 + Decimals uint8 +} + +type rawWeb2Envelope struct { + Method uint8 + Url string + Headers []byte + Body []byte + TimeoutMs uint64 + Extract []rawWeb2Extract +} + +// decodeWeb2QueryEnvelope decodes ReadSpec.query for web2 destinations. +func decodeWeb2QueryEnvelope(query []byte) (*web2QueryEnvelope, error) { + vals, err := web2EnvelopeArgs.Unpack(query) + if err != nil { + return nil, fmt.Errorf("failed to unpack Web2QueryEnvelope: %w", err) + } + raw := *abi.ConvertType(vals[0], new(rawWeb2Envelope)).(*rawWeb2Envelope) + + env := &web2QueryEnvelope{ + Method: web2Method(raw.Method), + URL: raw.Url, + Headers: raw.Headers, + Body: raw.Body, + TimeoutMs: raw.TimeoutMs, + } + for _, e := range raw.Extract { + env.Extract = append(env.Extract, web2Extract{ + Path: e.Path, + ValueType: extractValueType(e.ValueType), + Mode: extractMode(e.Mode), + Decimals: e.Decimals, + }) + } + + if env.Method > web2MethodPost { + return nil, fmt.Errorf("unknown web2 method %d", env.Method) + } + if len(env.Extract) == 0 { + return nil, fmt.Errorf("envelope has no extract entries") + } + if len(env.Extract) > maxExtractEntries { + return nil, fmt.Errorf("envelope has %d extract entries, max %d", len(env.Extract), maxExtractEntries) + } + for _, e := range env.Extract { + if e.ValueType > valueTypeBytes { + return nil, fmt.Errorf("unknown extract value type %d", e.ValueType) + } + if e.Mode != modeIdentical { + return nil, fmt.Errorf("unsupported extract mode %d, only IDENTICAL", e.Mode) + } + } + return env, nil +} diff --git a/universalClient/externalchains/web2/read_executor.go b/universalClient/externalchains/web2/read_executor.go new file mode 100644 index 00000000..752f6b6f --- /dev/null +++ b/universalClient/externalchains/web2/read_executor.go @@ -0,0 +1,424 @@ +// Package web2 executes web2 (HTTP) read requests: it fetches the declared +// endpoint, extracts the declared JSON fields, and canonically encodes them so +// read results are byte-identical across validators. +package web2 + +import ( + "bytes" + "context" + "encoding/hex" + "encoding/json" + "errors" + "fmt" + "io" + "math/big" + "net" + "net/http" + "strconv" + "strings" + "time" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/rs/zerolog" + + "github.com/pushchain/push-chain-node/universalClient/externalchains/common" + ucallbacktypes "github.com/pushchain/push-chain-node/x/ucallback/types" +) + +const ( + // DestinationPrefix identifies web2 read destinations, e.g. "web2:https". + DestinationPrefix = "web2:" + + maxResponseBytes = 64 * 1024 + maxExtractEntries = 16 + defaultTimeout = 5 * time.Second + maxTimeout = 15 * time.Second + maxRedirects = 5 +) + +// errBlockedRequest marks a request rejected by the SSRF guard (private/internal +// address, disallowed redirect). It is deterministic: every honest validator +// rejects the same envelope identically, so it becomes a votable ERROR rather +// than a transient retry. +var errBlockedRequest = errors.New("request blocked by ssrf guard") + +// TODO(core): a web2 read makes every validator fetch an attacker-chosen URL, +// so the fee is the only thing pricing that outbound work. The fee must NEVER +// be fully refunded on failure or no-quorum: a full refund lets an attacker +// drive the whole validator set at any endpoint for only tx gas (griefing / +// reflected load). Charge for execution regardless of read outcome. + +// Executor implements common.ReadRequestHandler for web2 destinations. +type Executor struct { + httpClient *http.Client + logger zerolog.Logger + // allowInsecureURL disables the https-only rule (tests only) + allowInsecureURL bool +} + +// NewExecutor creates a web2 read executor. Its HTTP client dials through an +// SSRF guard that blocks private/internal addresses on the initial request and +// on every redirect hop, and only connects to the exact IP it vetted (so DNS +// rebinding cannot swap in an internal address between check and dial). +func NewExecutor(logger zerolog.Logger) *Executor { + e := &Executor{ + logger: logger.With().Str("component", "web2_read_executor").Logger(), + } + e.httpClient = &http.Client{ + Timeout: maxTimeout, + Transport: &http.Transport{DialContext: e.dialContext}, + CheckRedirect: e.checkRedirect, + } + return e +} + +// dialContext resolves the target host and refuses any non-public address, then +// dials the vetted IP directly. Tests set allowInsecureURL to reach httptest +// servers on loopback. +func (e *Executor) dialContext(ctx context.Context, network, addr string) (net.Conn, error) { + if e.allowInsecureURL { + return (&net.Dialer{}).DialContext(ctx, network, addr) + } + + host, port, err := net.SplitHostPort(addr) + if err != nil { + return nil, err + } + + ips, err := net.DefaultResolver.LookupIPAddr(ctx, host) + if err != nil { + return nil, err + } + if len(ips) == 0 { + return nil, fmt.Errorf("no addresses for %s", host) + } + for _, ip := range ips { + if isDisallowedIP(ip.IP) { + return nil, fmt.Errorf("%w: %s resolves to non-public address %s", errBlockedRequest, host, ip.IP) + } + } + + dialer := &net.Dialer{} + var lastErr error + for _, ip := range ips { + conn, err := dialer.DialContext(ctx, network, net.JoinHostPort(ip.IP.String(), port)) + if err != nil { + lastErr = err + continue + } + return conn, nil + } + return nil, lastErr +} + +// checkRedirect keeps redirects https-only and bounded. The dialer still vets +// every hop's address; this only rejects scheme downgrades and redirect loops. +func (e *Executor) checkRedirect(req *http.Request, via []*http.Request) error { + if len(via) >= maxRedirects { + return fmt.Errorf("%w: too many redirects", errBlockedRequest) + } + if !e.allowInsecureURL && req.URL.Scheme != "https" { + return fmt.Errorf("%w: redirect to non-https url", errBlockedRequest) + } + return nil +} + +// isDisallowedIP reports whether an IP is one the guard must never connect to: +// loopback, private (RFC1918 / ULA), link-local (incl. 169.254.169.254 cloud +// metadata), carrier-grade NAT, multicast, or the unspecified address. +func isDisallowedIP(ip net.IP) bool { + if ip.IsLoopback() || ip.IsPrivate() || ip.IsUnspecified() || + ip.IsLinkLocalUnicast() || ip.IsLinkLocalMulticast() || ip.IsMulticast() { + return true + } + // Carrier-grade NAT 100.64.0.0/10 (RFC 6598) is not covered by IsPrivate. + if v4 := ip.To4(); v4 != nil && v4[0] == 100 && v4[1]&0xc0 == 64 { + return true + } + return false +} + +// ExecuteRead fetches the endpoint declared in the envelope, extracts the +// declared fields, and abi-encodes them in extract order. Deterministic +// failures (bad envelope, non-JSON response, missing path, 4xx) are votable +// ERROR observations; transport failures and 5xx are transient errors. +func (e *Executor) ExecuteRead(ctx context.Context, req *ucallbacktypes.ReadRequest) (*ucallbacktypes.ReadResult, error) { + env, err := decodeWeb2QueryEnvelope(req.Query) + if err != nil { + return common.NewReadErrorResult(ucallbacktypes.ReadErrorCode_READ_ERROR_INVALID_QUERY), nil + } + + if errResult := e.validateEnvelope(env); errResult != nil { + return errResult, nil + } + + body, errResult, err := e.fetch(ctx, env) + if err != nil { + return nil, err // transient + } + if errResult != nil { + return errResult, nil + } + + resultData, code, err := extractAndEncode(body, env.Extract) + if err != nil { + return common.NewReadErrorResult(code), nil + } + + // web2 has no block height or hash; the ballot covers result data only + return &ucallbacktypes.ReadResult{ + Status: ucallbacktypes.ReadStatus_READ_STATUS_SUCCESS, + ResultData: resultData, + }, nil +} + +// validateEnvelope enforces the v1 request constraints, returning a coded ERROR +// result on violation or nil when the envelope is acceptable. +func (e *Executor) validateEnvelope(env *web2QueryEnvelope) *ucallbacktypes.ReadResult { + if !e.allowInsecureURL && !strings.HasPrefix(env.URL, "https://") { + return common.NewReadErrorResult(ucallbacktypes.ReadErrorCode_READ_ERROR_INVALID_QUERY) + } + if env.Method == web2MethodGet && len(env.Body) > 0 { + return common.NewReadErrorResult(ucallbacktypes.ReadErrorCode_READ_ERROR_INVALID_QUERY) + } + return nil +} + +// fetch performs the HTTP request. Returns (body, nil, nil) on success, +// (nil, errorResult, nil) on deterministic failure, (nil, nil, err) on +// transient failure. +func (e *Executor) fetch(ctx context.Context, env *web2QueryEnvelope) ([]byte, *ucallbacktypes.ReadResult, error) { + timeout := defaultTimeout + if env.TimeoutMs > 0 { + timeout = min(time.Duration(env.TimeoutMs)*time.Millisecond, maxTimeout) + } + reqCtx, cancel := context.WithTimeout(ctx, timeout) + defer cancel() + + method := http.MethodGet + var reqBody io.Reader + if env.Method == web2MethodPost { + method = http.MethodPost + reqBody = bytes.NewReader(env.Body) + } + + httpReq, err := http.NewRequestWithContext(reqCtx, method, env.URL, reqBody) + if err != nil { + return nil, common.NewReadErrorResult(ucallbacktypes.ReadErrorCode_READ_ERROR_INVALID_QUERY), nil + } + + if len(env.Headers) > 0 { + var headers map[string]string + if err := json.Unmarshal(env.Headers, &headers); err != nil { + return nil, common.NewReadErrorResult(ucallbacktypes.ReadErrorCode_READ_ERROR_INVALID_QUERY), nil + } + for name, value := range headers { + httpReq.Header.Set(name, value) + } + } + + resp, err := e.httpClient.Do(httpReq) + if err != nil { + // A guard rejection is the same for every validator: votable ERROR. + // Any other transport error may be transient. + if errors.Is(err, errBlockedRequest) { + return nil, common.NewReadErrorResult(ucallbacktypes.ReadErrorCode_READ_ERROR_INVALID_QUERY), nil + + } + return nil, nil, fmt.Errorf("request failed: %w", err) // transient + } + defer func() { _ = resp.Body.Close() }() + + // 5xx, plus the transient 4xx codes 408 (Request Timeout) and 429 (Too Many + // Requests), mean "try again" — retry, never vote. Every other non-2xx is a + // deterministic answer from the endpoint and is votable. + if resp.StatusCode >= 500 || + resp.StatusCode == http.StatusRequestTimeout || + resp.StatusCode == http.StatusTooManyRequests { + return nil, nil, fmt.Errorf("endpoint returned status %d", resp.StatusCode) + } + if resp.StatusCode < 200 || resp.StatusCode >= 300 { + return nil, common.NewReadErrorResult(ucallbacktypes.ReadErrorCode_READ_ERROR_REVERTED), nil + } + + body, err := io.ReadAll(io.LimitReader(resp.Body, maxResponseBytes+1)) + if err != nil { + return nil, nil, fmt.Errorf("failed to read response: %w", err) // transient + } + if len(body) > maxResponseBytes { + return nil, common.NewReadErrorResult(ucallbacktypes.ReadErrorCode_READ_ERROR_INVALID_RESULT), nil + } + + return body, nil, nil +} + +// extractAndEncode applies each extract spec to the JSON response and +// abi-encodes the values in extract order. +func extractAndEncode(body []byte, extracts []web2Extract) ([]byte, ucallbacktypes.ReadErrorCode, error) { + decoder := json.NewDecoder(bytes.NewReader(body)) + decoder.UseNumber() + var root any + if err := decoder.Decode(&root); err != nil { + return nil, ucallbacktypes.ReadErrorCode_READ_ERROR_INVALID_RESULT, fmt.Errorf("response is not valid JSON: %w", err) + } + + args := make(abi.Arguments, 0, len(extracts)) + values := make([]any, 0, len(extracts)) + for _, ex := range extracts { + raw, err := resolveJSONPath(root, ex.Path) + if err != nil { + return nil, ucallbacktypes.ReadErrorCode_READ_ERROR_NOT_FOUND, err + } + + value, abiType, err := convertValue(raw, ex) + if err != nil { + return nil, ucallbacktypes.ReadErrorCode_READ_ERROR_INVALID_RESULT, fmt.Errorf("path %s: %w", ex.Path, err) + } + args = append(args, abi.Argument{Name: "v", Type: abiType}) + values = append(values, value) + } + + encoded, err := args.Pack(values...) + if err != nil { + return nil, ucallbacktypes.ReadErrorCode_READ_ERROR_INVALID_RESULT, fmt.Errorf("failed to encode result: %w", err) + } + return encoded, ucallbacktypes.ReadErrorCode_READ_ERROR_UNSPECIFIED, nil +} + +var ( + abiUint256, _ = abi.NewType("uint256", "", nil) + abiInt256, _ = abi.NewType("int256", "", nil) + abiBool, _ = abi.NewType("bool", "", nil) + abiString, _ = abi.NewType("string", "", nil) + abiBytes, _ = abi.NewType("bytes", "", nil) +) + +// convertValue converts a JSON value to the declared abi value. +func convertValue(raw any, ex web2Extract) (any, abi.Type, error) { + switch ex.ValueType { + case valueTypeUint256, valueTypeInt256: + num, err := scaledInteger(raw, ex.Decimals) + if err != nil { + return nil, abi.Type{}, err + } + if ex.ValueType == valueTypeUint256 { + if num.Sign() < 0 || num.BitLen() > 256 { + return nil, abi.Type{}, fmt.Errorf("value out of uint256 range") + } + return num, abiUint256, nil + } + if num.BitLen() > 255 { + return nil, abi.Type{}, fmt.Errorf("value out of int256 range") + } + return num, abiInt256, nil + + case valueTypeBool: + b, ok := raw.(bool) + if !ok { + return nil, abi.Type{}, fmt.Errorf("expected bool, got %T", raw) + } + return b, abiBool, nil + + case valueTypeString: + s, ok := raw.(string) + if !ok { + return nil, abi.Type{}, fmt.Errorf("expected string, got %T", raw) + } + return s, abiString, nil + + case valueTypeBytes: + s, ok := raw.(string) + if !ok || !strings.HasPrefix(s, "0x") { + return nil, abi.Type{}, fmt.Errorf("expected 0x-prefixed hex string") + } + decoded, err := hex.DecodeString(strings.TrimPrefix(s, "0x")) + if err != nil { + return nil, abi.Type{}, fmt.Errorf("invalid hex: %w", err) + } + return decoded, abiBytes, nil + + default: + return nil, abi.Type{}, fmt.Errorf("unknown value type %d", ex.ValueType) + } +} + +// scaledInteger parses a JSON number (or numeric string), scales it by +// 10^decimals, and truncates to an integer. big.Rat keeps float-formatted +// JSON exact (e.g. "3512.4471" with 8 decimals -> 351244710000). +func scaledInteger(raw any, decimals uint8) (*big.Int, error) { + var numStr string + switch v := raw.(type) { + case json.Number: + numStr = v.String() + case string: + numStr = v + default: + return nil, fmt.Errorf("expected number, got %T", raw) + } + + rat, ok := new(big.Rat).SetString(numStr) + if !ok { + return nil, fmt.Errorf("invalid number %q", numStr) + } + + scale := new(big.Int).Exp(big.NewInt(10), big.NewInt(int64(decimals)), nil) + rat.Mul(rat, new(big.Rat).SetInt(scale)) + + return new(big.Int).Quo(rat.Num(), rat.Denom()), nil +} + +// resolveJSONPath resolves a minimal JSONPath subset: "$" root, dot fields and +// array indexes, e.g. "$.data.items[0].price". +func resolveJSONPath(root any, path string) (any, error) { + if !strings.HasPrefix(path, "$") { + return nil, fmt.Errorf("path %s must start with $", path) + } + + current := root + rest := strings.TrimPrefix(path, "$") + for _, segment := range strings.Split(rest, ".") { + if segment == "" { + continue + } + + field := segment + var indexes []int + for strings.HasSuffix(field, "]") { + open := strings.LastIndex(field, "[") + if open < 0 { + return nil, fmt.Errorf("path %s has malformed index in %q", path, segment) + } + idx, err := strconv.Atoi(field[open+1 : len(field)-1]) + if err != nil || idx < 0 { + return nil, fmt.Errorf("path %s has invalid index in %q", path, segment) + } + indexes = append([]int{idx}, indexes...) + field = field[:open] + } + + if field != "" { + obj, ok := current.(map[string]any) + if !ok { + return nil, fmt.Errorf("path %s: %q is not an object", path, field) + } + value, ok := obj[field] + if !ok { + return nil, fmt.Errorf("path %s: field %q not found", path, field) + } + current = value + } + + for _, idx := range indexes { + arr, ok := current.([]any) + if !ok { + return nil, fmt.Errorf("path %s: indexing into non-array", path) + } + if idx >= len(arr) { + return nil, fmt.Errorf("path %s: index %d out of range", path, idx) + } + current = arr[idx] + } + } + + return current, nil +} diff --git a/universalClient/externalchains/web2/read_executor_test.go b/universalClient/externalchains/web2/read_executor_test.go new file mode 100644 index 00000000..a5725af0 --- /dev/null +++ b/universalClient/externalchains/web2/read_executor_test.go @@ -0,0 +1,428 @@ +package web2 + +import ( + "context" + "encoding/json" + "errors" + "math/big" + "net" + "net/http" + "net/http/httptest" + "testing" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/rs/zerolog" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + ucallbacktypes "github.com/pushchain/push-chain-node/x/ucallback/types" +) + +func packEnvelope(t *testing.T, env rawWeb2Envelope) []byte { + t.Helper() + data, err := web2EnvelopeArgs.Pack(env) + require.NoError(t, err) + return data +} + +func extractSpec(path string, valueType extractValueType, decimals uint8) rawWeb2Extract { + return rawWeb2Extract{Path: path, ValueType: uint8(valueType), Mode: uint8(modeIdentical), Decimals: decimals} +} + +func newTestExecutor(t *testing.T, handler http.HandlerFunc) (*Executor, string) { + t.Helper() + srv := httptest.NewServer(handler) + t.Cleanup(srv.Close) + + e := NewExecutor(zerolog.Nop()) + e.allowInsecureURL = true // httptest serves plain http + return e, srv.URL +} + +func jsonHandler(t *testing.T, wantMethod string, response any) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, wantMethod, r.Method) + require.NoError(t, json.NewEncoder(w).Encode(response)) + } +} + +func web2Request(t *testing.T, env rawWeb2Envelope) *ucallbacktypes.ReadRequest { + t.Helper() + return &ucallbacktypes.ReadRequest{ + RequestId: "0xreq1", + DestinationChain: "web2:https", + Query: packEnvelope(t, env), + } +} + +func TestExecuteRead_GetIdenticalFields(t *testing.T) { + e, url := newTestExecutor(t, jsonHandler(t, http.MethodGet, map[string]any{ + "status": "FINAL", + "winner": "TeamA", + "score": map[string]any{"a": 3, "b": 1}, + })) + + req := web2Request(t, rawWeb2Envelope{ + Method: uint8(web2MethodGet), + Url: url, + Extract: []rawWeb2Extract{ + extractSpec("$.status", valueTypeString, 0), + extractSpec("$.winner", valueTypeString, 0), + extractSpec("$.score.a", valueTypeUint256, 0), + }, + }) + + result, err := e.ExecuteRead(context.Background(), req) + require.NoError(t, err) + require.Equal(t, ucallbacktypes.ReadStatus_READ_STATUS_SUCCESS, result.Status) + + stringTy, _ := abi.NewType("string", "", nil) + uintTy, _ := abi.NewType("uint256", "", nil) + args := abi.Arguments{{Type: stringTy}, {Type: stringTy}, {Type: uintTy}} + vals, err := args.Unpack(result.ResultData) + require.NoError(t, err) + assert.Equal(t, "FINAL", vals[0]) + assert.Equal(t, "TeamA", vals[1]) + assert.Equal(t, big.NewInt(3), vals[2]) +} + +func TestExecuteRead_DecimalScaling(t *testing.T) { + e, url := newTestExecutor(t, jsonHandler(t, http.MethodGet, map[string]any{ + "price": 3512.4471, + })) + + req := web2Request(t, rawWeb2Envelope{ + Method: uint8(web2MethodGet), + Url: url, + Extract: []rawWeb2Extract{extractSpec("$.price", valueTypeUint256, 8)}, + }) + + result, err := e.ExecuteRead(context.Background(), req) + require.NoError(t, err) + require.Equal(t, ucallbacktypes.ReadStatus_READ_STATUS_SUCCESS, result.Status) + + assert.Equal(t, big.NewInt(351244710000), new(big.Int).SetBytes(result.ResultData)) +} + +func TestExecuteRead_PostBody(t *testing.T) { + e, url := newTestExecutor(t, func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, http.MethodPost, r.Method) + assert.Equal(t, "application/json", r.Header.Get("Content-Type")) + var body map[string]string + require.NoError(t, json.NewDecoder(r.Body).Decode(&body)) + assert.Equal(t, "{ token { decimals } }", body["query"]) + require.NoError(t, json.NewEncoder(w).Encode(map[string]any{ + "data": map[string]any{"token": map[string]any{"decimals": 18}}, + })) + }) + + req := web2Request(t, rawWeb2Envelope{ + Method: uint8(web2MethodPost), + Url: url, + Headers: []byte(`{"content-type":"application/json"}`), + Body: []byte(`{"query":"{ token { decimals } }"}`), + Extract: []rawWeb2Extract{extractSpec("$.data.token.decimals", valueTypeUint256, 0)}, + }) + + result, err := e.ExecuteRead(context.Background(), req) + require.NoError(t, err) + require.Equal(t, ucallbacktypes.ReadStatus_READ_STATUS_SUCCESS, result.Status) + assert.Equal(t, big.NewInt(18), new(big.Int).SetBytes(result.ResultData)) +} + +func TestExecuteRead_ArrayIndexPath(t *testing.T) { + e, url := newTestExecutor(t, jsonHandler(t, http.MethodGet, map[string]any{ + "items": []any{map[string]any{"ok": true}, map[string]any{"ok": false}}, + })) + + req := web2Request(t, rawWeb2Envelope{ + Method: uint8(web2MethodGet), + Url: url, + Extract: []rawWeb2Extract{extractSpec("$.items[1].ok", valueTypeBool, 0)}, + }) + + result, err := e.ExecuteRead(context.Background(), req) + require.NoError(t, err) + require.Equal(t, ucallbacktypes.ReadStatus_READ_STATUS_SUCCESS, result.Status) + + boolTy, _ := abi.NewType("bool", "", nil) + vals, err := abi.Arguments{{Type: boolTy}}.Unpack(result.ResultData) + require.NoError(t, err) + assert.Equal(t, false, vals[0]) +} + +func TestExecuteRead_VotableErrors(t *testing.T) { + t.Run("invalid envelope", func(t *testing.T) { + e := NewExecutor(zerolog.Nop()) + result, err := e.ExecuteRead(context.Background(), &ucallbacktypes.ReadRequest{Query: []byte{0x01}}) + require.NoError(t, err) + assert.Equal(t, ucallbacktypes.ReadStatus_READ_STATUS_ERROR, result.Status) + assert.Equal(t, ucallbacktypes.ReadErrorCode_READ_ERROR_INVALID_QUERY, result.ErrorCode) + }) + + t.Run("non-https url", func(t *testing.T) { + e := NewExecutor(zerolog.Nop()) + req := web2Request(t, rawWeb2Envelope{ + Method: uint8(web2MethodGet), + Url: "http://insecure.example.com", + Extract: []rawWeb2Extract{extractSpec("$.x", valueTypeString, 0)}, + }) + result, err := e.ExecuteRead(context.Background(), req) + require.NoError(t, err) + assert.Equal(t, ucallbacktypes.ReadStatus_READ_STATUS_ERROR, result.Status) + assert.Equal(t, ucallbacktypes.ReadErrorCode_READ_ERROR_INVALID_QUERY, result.ErrorCode) + }) + + t.Run("non-identical mode not supported", func(t *testing.T) { + e := NewExecutor(zerolog.Nop()) + req := web2Request(t, rawWeb2Envelope{ + Method: uint8(web2MethodGet), + Url: "https://api.example.com", + Extract: []rawWeb2Extract{ + {Path: "$.price", ValueType: uint8(valueTypeUint256), Mode: 1, Decimals: 8}, + }, + }) + result, err := e.ExecuteRead(context.Background(), req) + require.NoError(t, err) + assert.Equal(t, ucallbacktypes.ReadStatus_READ_STATUS_ERROR, result.Status) + }) + + t.Run("GET with body", func(t *testing.T) { + e := NewExecutor(zerolog.Nop()) + req := web2Request(t, rawWeb2Envelope{ + Method: uint8(web2MethodGet), + Url: "https://api.example.com", + Body: []byte("nope"), + Extract: []rawWeb2Extract{extractSpec("$.x", valueTypeString, 0)}, + }) + result, err := e.ExecuteRead(context.Background(), req) + require.NoError(t, err) + assert.Equal(t, ucallbacktypes.ReadStatus_READ_STATUS_ERROR, result.Status) + }) + + t.Run("missing path", func(t *testing.T) { + e, url := newTestExecutor(t, jsonHandler(t, http.MethodGet, map[string]any{"a": 1})) + req := web2Request(t, rawWeb2Envelope{ + Method: uint8(web2MethodGet), + Url: url, + Extract: []rawWeb2Extract{extractSpec("$.missing", valueTypeUint256, 0)}, + }) + result, err := e.ExecuteRead(context.Background(), req) + require.NoError(t, err) + assert.Equal(t, ucallbacktypes.ReadStatus_READ_STATUS_ERROR, result.Status) + assert.Equal(t, ucallbacktypes.ReadErrorCode_READ_ERROR_NOT_FOUND, result.ErrorCode) + }) + + t.Run("type mismatch", func(t *testing.T) { + e, url := newTestExecutor(t, jsonHandler(t, http.MethodGet, map[string]any{"a": "text"})) + req := web2Request(t, rawWeb2Envelope{ + Method: uint8(web2MethodGet), + Url: url, + Extract: []rawWeb2Extract{extractSpec("$.a", valueTypeBool, 0)}, + }) + result, err := e.ExecuteRead(context.Background(), req) + require.NoError(t, err) + assert.Equal(t, ucallbacktypes.ReadStatus_READ_STATUS_ERROR, result.Status) + assert.Equal(t, ucallbacktypes.ReadErrorCode_READ_ERROR_INVALID_RESULT, result.ErrorCode) + }) + + t.Run("non-JSON response", func(t *testing.T) { + e, url := newTestExecutor(t, func(w http.ResponseWriter, r *http.Request) { + _, _ = w.Write([]byte("not json")) + }) + req := web2Request(t, rawWeb2Envelope{ + Method: uint8(web2MethodGet), + Url: url, + Extract: []rawWeb2Extract{extractSpec("$.a", valueTypeString, 0)}, + }) + result, err := e.ExecuteRead(context.Background(), req) + require.NoError(t, err) + assert.Equal(t, ucallbacktypes.ReadStatus_READ_STATUS_ERROR, result.Status) + assert.Equal(t, ucallbacktypes.ReadErrorCode_READ_ERROR_INVALID_RESULT, result.ErrorCode) + }) + + t.Run("404 status", func(t *testing.T) { + e, url := newTestExecutor(t, func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusNotFound) + }) + req := web2Request(t, rawWeb2Envelope{ + Method: uint8(web2MethodGet), + Url: url, + Extract: []rawWeb2Extract{extractSpec("$.a", valueTypeString, 0)}, + }) + result, err := e.ExecuteRead(context.Background(), req) + require.NoError(t, err) + assert.Equal(t, ucallbacktypes.ReadStatus_READ_STATUS_ERROR, result.Status) + assert.Equal(t, ucallbacktypes.ReadErrorCode_READ_ERROR_REVERTED, result.ErrorCode) + }) +} + +func TestExecuteRead_TransientErrors(t *testing.T) { + t.Run("500 status", func(t *testing.T) { + e, url := newTestExecutor(t, func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusInternalServerError) + }) + req := web2Request(t, rawWeb2Envelope{ + Method: uint8(web2MethodGet), + Url: url, + Extract: []rawWeb2Extract{extractSpec("$.a", valueTypeString, 0)}, + }) + result, err := e.ExecuteRead(context.Background(), req) + require.Error(t, err) + assert.Nil(t, result) + }) + + t.Run("unreachable endpoint", func(t *testing.T) { + e := NewExecutor(zerolog.Nop()) + e.allowInsecureURL = true + req := web2Request(t, rawWeb2Envelope{ + Method: uint8(web2MethodGet), + Url: "http://127.0.0.1:1", + TimeoutMs: 500, + Extract: []rawWeb2Extract{extractSpec("$.a", valueTypeString, 0)}, + }) + result, err := e.ExecuteRead(context.Background(), req) + require.Error(t, err) + assert.Nil(t, result) + }) + + // 408 and 429 are retryable 4xx codes: retry, never vote. + for _, tc := range []struct { + name string + code int + }{ + {"408 request timeout", http.StatusRequestTimeout}, + {"429 too many requests", http.StatusTooManyRequests}, + } { + t.Run(tc.name, func(t *testing.T) { + e, url := newTestExecutor(t, func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(tc.code) + }) + req := web2Request(t, rawWeb2Envelope{ + Method: uint8(web2MethodGet), + Url: url, + Extract: []rawWeb2Extract{extractSpec("$.a", valueTypeString, 0)}, + }) + result, err := e.ExecuteRead(context.Background(), req) + require.Error(t, err) + assert.Nil(t, result) + }) + } +} + +func TestExecuteRead_SSRFGuard(t *testing.T) { + // guard is active only when allowInsecureURL is false + blocked := []string{ + "https://127.0.0.1/x", + "https://[::1]/x", + "https://169.254.169.254/latest/meta-data/", + "https://10.0.0.1/x", + "https://192.168.1.1/x", + "https://172.16.0.1/x", + "https://100.64.0.1/x", + "https://0.0.0.0/x", + } + for _, target := range blocked { + t.Run(target, func(t *testing.T) { + e := NewExecutor(zerolog.Nop()) + req := web2Request(t, rawWeb2Envelope{ + Method: uint8(web2MethodGet), + Url: target, + TimeoutMs: 1000, + Extract: []rawWeb2Extract{extractSpec("$.x", valueTypeString, 0)}, + }) + result, err := e.ExecuteRead(context.Background(), req) + require.NoError(t, err) // deterministic, not transient + assert.Equal(t, ucallbacktypes.ReadStatus_READ_STATUS_ERROR, result.Status) + }) + } +} + +func TestCheckRedirect(t *testing.T) { + e := NewExecutor(zerolog.Nop()) + + mustReq := func(rawURL string) *http.Request { + r, err := http.NewRequest(http.MethodGet, rawURL, nil) + require.NoError(t, err) + return r + } + + // https redirect within the hop budget is allowed + assert.NoError(t, e.checkRedirect(mustReq("https://example.com/next"), make([]*http.Request, 1))) + + // scheme downgrade to http is blocked + err := e.checkRedirect(mustReq("http://example.com/next"), make([]*http.Request, 1)) + require.Error(t, err) + assert.True(t, errors.Is(err, errBlockedRequest)) + + // too many redirects is blocked + err = e.checkRedirect(mustReq("https://example.com/next"), make([]*http.Request, maxRedirects)) + require.Error(t, err) + assert.True(t, errors.Is(err, errBlockedRequest)) +} + +func TestIsDisallowedIP(t *testing.T) { + disallowed := []string{ + "127.0.0.1", "::1", "10.1.2.3", "172.16.5.5", "192.168.0.1", + "169.254.169.254", "100.64.0.1", "0.0.0.0", "fe80::1", "fc00::1", "224.0.0.1", + // IPv4-mapped IPv6 must not slip past the v4-range checks + "::ffff:127.0.0.1", "::ffff:169.254.169.254", "::ffff:10.0.0.1", + } + for _, s := range disallowed { + assert.True(t, isDisallowedIP(net.ParseIP(s)), "%s should be blocked", s) + } + + allowed := []string{"8.8.8.8", "1.1.1.1", "93.184.216.34", "2606:2800:220:1::1", "100.63.255.255", "100.128.0.1"} + for _, s := range allowed { + assert.False(t, isDisallowedIP(net.ParseIP(s)), "%s should be allowed", s) + } +} + +func TestScaledInteger(t *testing.T) { + cases := []struct { + in string + decimals uint8 + want string + }{ + {"3512.4471", 8, "351244710000"}, + {"100", 0, "100"}, + {"0.5", 2, "50"}, + {"1.999", 0, "1"}, // truncates + {"-2.5", 1, "-25"}, + } + for _, tc := range cases { + got, err := scaledInteger(json.Number(tc.in), tc.decimals) + require.NoError(t, err, tc.in) + assert.Equal(t, tc.want, got.String(), tc.in) + } + + _, err := scaledInteger(json.Number("not-a-number"), 0) + assert.Error(t, err) + _, err = scaledInteger(true, 0) + assert.Error(t, err) +} + +func TestDecodeWeb2QueryEnvelope_Invalid(t *testing.T) { + t.Run("garbage bytes", func(t *testing.T) { + _, err := decodeWeb2QueryEnvelope([]byte{0x01, 0x02}) + assert.Error(t, err) + }) + + t.Run("no extract entries", func(t *testing.T) { + data, err := web2EnvelopeArgs.Pack(rawWeb2Envelope{Method: 0, Url: "https://x"}) + require.NoError(t, err) + _, err = decodeWeb2QueryEnvelope(data) + assert.Error(t, err) + }) + + t.Run("unknown method", func(t *testing.T) { + data, err := web2EnvelopeArgs.Pack(rawWeb2Envelope{ + Method: 9, + Url: "https://x", + Extract: []rawWeb2Extract{{Path: "$.a"}}, + }) + require.NoError(t, err) + _, err = decodeWeb2QueryEnvelope(data) + assert.Error(t, err) + }) +} diff --git a/universalClient/pushcore/pushCore.go b/universalClient/pushcore/pushCore.go index 647b548e..600c4836 100644 --- a/universalClient/pushcore/pushCore.go +++ b/universalClient/pushcore/pushCore.go @@ -16,6 +16,7 @@ import ( "github.com/cosmos/cosmos-sdk/types/tx" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/cosmos/cosmos-sdk/x/authz" + ucallbacktypes "github.com/pushchain/push-chain-node/x/ucallback/types" uexecutortypes "github.com/pushchain/push-chain-node/x/uexecutor/types" uregistrytypes "github.com/pushchain/push-chain-node/x/uregistry/types" utsstypes "github.com/pushchain/push-chain-node/x/utss/types" @@ -34,6 +35,7 @@ type Client struct { uvalidatorClients []uvalidatortypes.QueryClient // Universal validator query clients utssClients []utsstypes.QueryClient // TSS query clients uexecutorClients []uexecutortypes.QueryClient // Executor query clients (for gas price queries) + ucallbackClients []ucallbacktypes.QueryClient // Callback query clients (for pending read requests) cmtClients []cmtservice.ServiceClient // CometBFT service clients txClients []tx.ServiceClient // Transaction service clients authzClients []authz.QueryClient // AuthZ query clients @@ -65,6 +67,7 @@ func New(urls []string, logger zerolog.Logger) (*Client, error) { c.uvalidatorClients = append(c.uvalidatorClients, uvalidatortypes.NewQueryClient(conn)) c.utssClients = append(c.utssClients, utsstypes.NewQueryClient(conn)) c.uexecutorClients = append(c.uexecutorClients, uexecutortypes.NewQueryClient(conn)) + c.ucallbackClients = append(c.ucallbackClients, ucallbacktypes.NewQueryClient(conn)) c.cmtClients = append(c.cmtClients, cmtservice.NewServiceClient(conn)) c.txClients = append(c.txClients, tx.NewServiceClient(conn)) c.authzClients = append(c.authzClients, authz.NewQueryClient(conn)) @@ -93,6 +96,7 @@ func (c *Client) Close() error { c.uvalidatorClients = nil c.utssClients = nil c.uexecutorClients = nil + c.ucallbackClients = nil c.cmtClients = nil c.txClients = nil c.authzClients = nil @@ -367,6 +371,31 @@ func (c *Client) GetAllPendingOutbounds(ctx context.Context) ([]*uexecutortypes. return resp.Entries, resp.Outbounds, nil } +// GetAllPendingReadRequests retrieves up to the first 1000 pending external read +// requests from Push Chain. The query already withholds requests past their expiry +// height, so validators never take on work that can no longer be fulfilled in time. +func (c *Client) GetAllPendingReadRequests(ctx context.Context) ([]*ucallbacktypes.ReadRequest, error) { + return retryWithRoundRobin( + len(c.ucallbackClients), + &c.rr, + func(idx int) ([]*ucallbacktypes.ReadRequest, error) { + resp, err := c.ucallbackClients[idx].AllPendingReadRequests(ctx, &ucallbacktypes.QueryAllPendingReadRequestsRequest{ + Pagination: &query.PageRequest{Limit: 1000}, + }) + if err != nil { + return nil, err + } + requests := make([]*ucallbacktypes.ReadRequest, 0, len(resp.Reads)) + for i := range resp.Reads { + requests = append(requests, resp.Reads[i].Request) + } + return requests, nil + }, + "GetAllPendingReadRequests", + c.logger, + ) +} + // createGRPCConnection creates a gRPC connection with appropriate transport security. // It automatically detects whether to use TLS based on the URL scheme // and adds default port 9090 if no port is specified. diff --git a/universalClient/pushcore/pushCore_test.go b/universalClient/pushcore/pushCore_test.go index 323372b4..964540f7 100644 --- a/universalClient/pushcore/pushCore_test.go +++ b/universalClient/pushcore/pushCore_test.go @@ -10,6 +10,7 @@ import ( "github.com/cosmos/cosmos-sdk/types/tx" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/cosmos/cosmos-sdk/x/authz" + ucallbacktypes "github.com/pushchain/push-chain-node/x/ucallback/types" uexecutortypes "github.com/pushchain/push-chain-node/x/uexecutor/types" uregistrytypes "github.com/pushchain/push-chain-node/x/uregistry/types" utsstypes "github.com/pushchain/push-chain-node/x/utss/types" @@ -823,6 +824,73 @@ func TestClient_GetAllPendingOutbounds(t *testing.T) { }) } +func TestClient_GetAllPendingReadRequests(t *testing.T) { + logger := zerolog.Nop() + ctx := context.Background() + + t.Run("no endpoints configured", func(t *testing.T) { + client := &Client{ + logger: logger, + ucallbackClients: []ucallbacktypes.QueryClient{}, + } + + reqs, err := client.GetAllPendingReadRequests(ctx) + require.Error(t, err) + assert.Contains(t, err.Error(), "no endpoints configured") + assert.Nil(t, reqs) + }) + + t.Run("successful query maps UniversalRead.Request", func(t *testing.T) { + mockClient := &mockUCallbackQueryClient{ + allPendingReadsResp: &ucallbacktypes.QueryAllPendingReadRequestsResponse{ + Reads: []ucallbacktypes.UniversalRead{ + {Id: "0xr1", Request: &ucallbacktypes.ReadRequest{RequestId: "0xr1", DestinationChain: "eip155:1"}}, + {Id: "0xr2", Request: &ucallbacktypes.ReadRequest{RequestId: "0xr2", DestinationChain: "web2:https"}}, + }, + }, + } + + client := &Client{ + logger: logger, + ucallbackClients: []ucallbacktypes.QueryClient{mockClient}, + } + + reqs, err := client.GetAllPendingReadRequests(ctx) + require.NoError(t, err) + require.Len(t, reqs, 2) + assert.Equal(t, "0xr1", reqs[0].RequestId) + assert.Equal(t, "web2:https", reqs[1].DestinationChain) + }) + + t.Run("empty response", func(t *testing.T) { + mockClient := &mockUCallbackQueryClient{ + allPendingReadsResp: &ucallbacktypes.QueryAllPendingReadRequestsResponse{}, + } + + client := &Client{ + logger: logger, + ucallbackClients: []ucallbacktypes.QueryClient{mockClient}, + } + + reqs, err := client.GetAllPendingReadRequests(ctx) + require.NoError(t, err) + assert.Empty(t, reqs) + }) + + t.Run("all endpoints fail", func(t *testing.T) { + client := &Client{ + logger: logger, + ucallbackClients: []ucallbacktypes.QueryClient{ + &mockUCallbackQueryClient{err: assert.AnError}, + }, + } + + reqs, err := client.GetAllPendingReadRequests(ctx) + require.Error(t, err) + assert.Nil(t, reqs) + }) +} + func TestClient_GetGasPrice_NilResponse(t *testing.T) { logger := zerolog.Nop() mockClient := &mockUExecutorQueryClient{ @@ -965,10 +1033,10 @@ func (m *mockUValidatorQueryClient) UniversalValidator(ctx context.Context, req type mockUTSSQueryClient struct { utsstypes.QueryClient - currentKeyResp *utsstypes.QueryCurrentKeyResponse - pendingTssEventsResp *utsstypes.QueryAllPendingTssEventsResponse - pendingFundMigrationsResp *utsstypes.QueryPendingFundMigrationsResponse - err error + currentKeyResp *utsstypes.QueryCurrentKeyResponse + pendingTssEventsResp *utsstypes.QueryAllPendingTssEventsResponse + pendingFundMigrationsResp *utsstypes.QueryPendingFundMigrationsResponse + err error } func (m *mockUTSSQueryClient) CurrentKey(ctx context.Context, req *utsstypes.QueryCurrentKeyRequest, opts ...grpc.CallOption) (*utsstypes.QueryCurrentKeyResponse, error) { @@ -1084,3 +1152,16 @@ func (m *mockAuthAccountQueryClient) Account(ctx context.Context, req *authtypes } return m.accountResp, nil } + +type mockUCallbackQueryClient struct { + ucallbacktypes.QueryClient + allPendingReadsResp *ucallbacktypes.QueryAllPendingReadRequestsResponse + err error +} + +func (m *mockUCallbackQueryClient) AllPendingReadRequests(ctx context.Context, req *ucallbacktypes.QueryAllPendingReadRequestsRequest, opts ...grpc.CallOption) (*ucallbacktypes.QueryAllPendingReadRequestsResponse, error) { + if m.err != nil { + return nil, m.err + } + return m.allPendingReadsResp, nil +} diff --git a/universalClient/pushsigner/grant_verifier.go b/universalClient/pushsigner/grant_verifier.go index a4e92b4d..ef507f39 100644 --- a/universalClient/pushsigner/grant_verifier.go +++ b/universalClient/pushsigner/grant_verifier.go @@ -26,6 +26,7 @@ var requiredMsgGrants = []string{ "/uexecutor.v1.MsgVoteOutbound", "/utss.v1.MsgVoteTssKeyProcess", "/utss.v1.MsgVoteFundMigration", + "/ucallback.v1.MsgVoteReadResult", } // GrantInfo represents information about a single AuthZ grant. diff --git a/universalClient/pushsigner/grant_verifier_test.go b/universalClient/pushsigner/grant_verifier_test.go index 2c0ec770..ecb67089 100644 --- a/universalClient/pushsigner/grant_verifier_test.go +++ b/universalClient/pushsigner/grant_verifier_test.go @@ -28,6 +28,7 @@ func TestVerifyGrants(t *testing.T) { {Granter: granter, MessageType: "/uexecutor.v1.MsgVoteOutbound", Expiration: &futureTime}, {Granter: granter, MessageType: "/utss.v1.MsgVoteTssKeyProcess", Expiration: &futureTime}, {Granter: granter, MessageType: "/utss.v1.MsgVoteFundMigration", Expiration: &futureTime}, + {Granter: granter, MessageType: "/ucallback.v1.MsgVoteReadResult", Expiration: &futureTime}, } msgs, err := verifyGrants(grants, granter) @@ -47,6 +48,7 @@ func TestVerifyGrants(t *testing.T) { {Granter: granter, MessageType: "/uexecutor.v1.MsgVoteOutbound", Expiration: nil}, {Granter: granter, MessageType: "/utss.v1.MsgVoteTssKeyProcess", Expiration: nil}, {Granter: granter, MessageType: "/utss.v1.MsgVoteFundMigration", Expiration: nil}, + {Granter: granter, MessageType: "/ucallback.v1.MsgVoteReadResult", Expiration: nil}, } msgs, err := verifyGrants(grants, granter) @@ -115,6 +117,7 @@ func TestVerifyGrants(t *testing.T) { {Granter: granter, MessageType: "/uexecutor.v1.MsgVoteOutbound", Expiration: &futureTime}, {Granter: granter, MessageType: "/utss.v1.MsgVoteTssKeyProcess", Expiration: &futureTime}, {Granter: granter, MessageType: "/utss.v1.MsgVoteFundMigration", Expiration: &futureTime}, + {Granter: granter, MessageType: "/ucallback.v1.MsgVoteReadResult", Expiration: &futureTime}, } msgs, err := verifyGrants(grants, granter) @@ -129,6 +132,7 @@ func TestVerifyGrants(t *testing.T) { {Granter: granter, MessageType: "/uexecutor.v1.MsgVoteOutbound", Expiration: &futureTime}, {Granter: granter, MessageType: "/utss.v1.MsgVoteTssKeyProcess", Expiration: &futureTime}, {Granter: granter, MessageType: "/utss.v1.MsgVoteFundMigration", Expiration: &futureTime}, + {Granter: granter, MessageType: "/ucallback.v1.MsgVoteReadResult", Expiration: &futureTime}, {Granter: granter, MessageType: "/some.other.v1.MsgNotRequired", Expiration: &futureTime}, // Extra grant } diff --git a/universalClient/pushsigner/pushsigner.go b/universalClient/pushsigner/pushsigner.go index 8e8dcbfe..af14c153 100644 --- a/universalClient/pushsigner/pushsigner.go +++ b/universalClient/pushsigner/pushsigner.go @@ -24,6 +24,7 @@ import ( "github.com/pushchain/push-chain-node/universalClient/config" "github.com/pushchain/push-chain-node/universalClient/pushcore" "github.com/pushchain/push-chain-node/universalClient/pushsigner/keys" + ucallbacktypes "github.com/pushchain/push-chain-node/x/ucallback/types" uexecutortypes "github.com/pushchain/push-chain-node/x/uexecutor/types" ) @@ -132,6 +133,11 @@ func (s *Signer) VoteFundMigration(ctx context.Context, migrationID uint64, txHa return voteFundMigration(ctx, s, s.log, s.granter, migrationID, txHash, success) } +// VoteReadResult votes on an external read observation. +func (s *Signer) VoteReadResult(ctx context.Context, requestID string, result *ucallbacktypes.ReadResult) (string, error) { + return voteReadResult(ctx, s, s.log, s.granter, requestID, result) +} + // signAndBroadcastAuthZTx signs and broadcasts an AuthZ transaction func (s *Signer) signAndBroadcastAuthZTx( ctx context.Context, @@ -411,6 +417,7 @@ func createClientContext(kr cosmoskeyring.Keyring, chainID string) client.Contex stakingtypes.RegisterInterfaces(interfaceRegistry) govtypes.RegisterInterfaces(interfaceRegistry) uexecutortypes.RegisterInterfaces(interfaceRegistry) + ucallbacktypes.RegisterInterfaces(interfaceRegistry) cdc := codec.NewProtoCodec(interfaceRegistry) txConfig := authtx.NewTxConfig(cdc, []signing.SignMode{signing.SignMode_SIGN_MODE_DIRECT}) diff --git a/universalClient/pushsigner/pushsigner_test.go b/universalClient/pushsigner/pushsigner_test.go index 331a407e..c6cd25b9 100644 --- a/universalClient/pushsigner/pushsigner_test.go +++ b/universalClient/pushsigner/pushsigner_test.go @@ -18,6 +18,7 @@ import ( "github.com/pushchain/push-chain-node/universalClient/config" "github.com/pushchain/push-chain-node/universalClient/pushcore" "github.com/pushchain/push-chain-node/universalClient/pushsigner/keys" + ucallbacktypes "github.com/pushchain/push-chain-node/x/ucallback/types" uexecutortypes "github.com/pushchain/push-chain-node/x/uexecutor/types" ) @@ -625,6 +626,35 @@ func TestVoteFundMigrationFailure(t *testing.T) { assert.Equal(t, "VOTE_OK", txHash) } +func TestVoteReadResult(t *testing.T) { + result := &ucallbacktypes.ReadResult{ + Status: ucallbacktypes.ReadStatus_READ_STATUS_SUCCESS, + ResultData: []byte{0xaa}, + } + + t.Run("successful vote", func(t *testing.T) { + signer := createTestSigner(t, successMock(t)) + txHash, err := signer.VoteReadResult(context.Background(), "0xreq1", result) + require.NoError(t, err) + assert.Equal(t, "VOTE_OK", txHash) + }) + + t.Run("error observation votes too", func(t *testing.T) { + signer := createTestSigner(t, successMock(t)) + errResult := &ucallbacktypes.ReadResult{Status: ucallbacktypes.ReadStatus_READ_STATUS_ERROR} + txHash, err := signer.VoteReadResult(context.Background(), "0xreq2", errResult) + require.NoError(t, err) + assert.Equal(t, "VOTE_OK", txHash) + }) + + t.Run("broadcast failure", func(t *testing.T) { + signer := createTestSigner(t, failMock(t)) + _, err := signer.VoteReadResult(context.Background(), "0xreq1", result) + require.Error(t, err) + assert.Contains(t, err.Error(), "failed to broadcast vote") + }) +} + func TestVoteOnChainRejection(t *testing.T) { mock := &mockChainClient{ getAccountFn: func(ctx context.Context, address string) (*authtypes.QueryAccountResponse, error) { diff --git a/universalClient/pushsigner/vote.go b/universalClient/pushsigner/vote.go index 3312f463..593375c5 100644 --- a/universalClient/pushsigner/vote.go +++ b/universalClient/pushsigner/vote.go @@ -8,6 +8,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/rs/zerolog" + ucallbacktypes "github.com/pushchain/push-chain-node/x/ucallback/types" uexecutortypes "github.com/pushchain/push-chain-node/x/uexecutor/types" utsstypes "github.com/pushchain/push-chain-node/x/utss/types" ) @@ -105,6 +106,24 @@ func waitForTxConfirmation(ctx context.Context, client chainClient, txHash strin } } +// voteReadResult votes on an external read observation +func voteReadResult( + ctx context.Context, + signer *Signer, + log zerolog.Logger, + granter string, + requestID string, + result *ucallbacktypes.ReadResult, +) (string, error) { + msg := &ucallbacktypes.MsgVoteReadResult{ + Signer: granter, + RequestId: requestID, + Result: result, + } + memo := fmt.Sprintf("Vote read result: %s", requestID) + return vote(ctx, signer, log, msg, memo) +} + // voteInbound votes on an inbound transaction func voteInbound( ctx context.Context, diff --git a/universalClient/pushwatcher/client.go b/universalClient/pushwatcher/client.go index 351b38b9..875400f8 100644 --- a/universalClient/pushwatcher/client.go +++ b/universalClient/pushwatcher/client.go @@ -9,28 +9,36 @@ import ( "github.com/pushchain/push-chain-node/universalClient/config" "github.com/pushchain/push-chain-node/universalClient/db" "github.com/pushchain/push-chain-node/universalClient/externalchains/common" + "github.com/pushchain/push-chain-node/universalClient/externalchains/web2" "github.com/pushchain/push-chain-node/universalClient/pushcore" + "github.com/pushchain/push-chain-node/universalClient/pushsigner" + "github.com/pushchain/push-chain-node/universalClient/store" "github.com/rs/zerolog" ) // Client implements the ChainClient interface for Push chain type Client struct { - logger zerolog.Logger - pushCore *pushcore.Client - database *db.DB - eventListener *EventListener - eventCleaner *common.EventCleaner - ctx context.Context - cancel context.CancelFunc + logger zerolog.Logger + pushCore *pushcore.Client + database *db.DB + eventListener *EventListener + eventCleaner *common.EventCleaner + eventProcessor *EventProcessor + ctx context.Context + cancel context.CancelFunc } -// NewClient creates a new Push chain client +// NewClient creates a new Push chain client. +// pushSigner and chainResolver may be nil; the READ_REQUEST handler is only +// registered when both are present. func NewClient( database *db.DB, chainConfig *config.ChainSpecificConfig, pushCore *pushcore.Client, chainID string, logger zerolog.Logger, + pushSigner *pushsigner.Signer, + chainResolver ChainResolver, ) (*Client, error) { // Normalize nil config so downstream uses don't need nil guards. if chainConfig == nil { @@ -64,6 +72,22 @@ func NewClient( eventCleaner: eventCleaner, } + eventProcessor, err := NewEventProcessor(database, eventListener.cfg.PollInterval, logger) + if err != nil { + return nil, fmt.Errorf("failed to create event processor: %w", err) + } + + // READ_REQUEST events are executed on their destination chains (via + // chainResolver) and the results voted back. + if pushSigner != nil && chainResolver != nil { + readEventProcessor, err := NewReadEventProcessor(pushSigner, chainResolver, web2.NewExecutor(logger), database, logger) + if err != nil { + return nil, fmt.Errorf("failed to create read event processor: %w", err) + } + eventProcessor.RegisterHandler(store.EventTypeReadRequest, readEventProcessor) + } + client.eventProcessor = eventProcessor + return client, nil } @@ -85,6 +109,13 @@ func (c *Client) Start(ctx context.Context) error { } } + // Start event processor + if c.eventProcessor != nil { + if err := c.eventProcessor.Start(c.ctx); err != nil { + return fmt.Errorf("failed to start event processor: %w", err) + } + } + c.logger.Info().Msg("Push chain client started successfully") return nil } @@ -110,6 +141,13 @@ func (c *Client) Stop() error { c.eventCleaner.Stop() } + // Stop event processor + if c.eventProcessor != nil { + if err := c.eventProcessor.Stop(); err != nil { + c.logger.Error().Err(err).Str("subsystem", "event_processor").Msg("subsystem failed to stop") + } + } + c.logger.Info().Msg("Push chain client stopped") return nil } diff --git a/universalClient/pushwatcher/client_test.go b/universalClient/pushwatcher/client_test.go index 26877bea..8df232c4 100644 --- a/universalClient/pushwatcher/client_test.go +++ b/universalClient/pushwatcher/client_test.go @@ -34,7 +34,7 @@ func TestNewClient(t *testing.T) { pc := newTestPushCoreClient() t.Run("success with nil config", func(t *testing.T) { - client, err := NewClient(database, nil, pc, "push-chain", logger) + client, err := NewClient(database, nil, pc, "push-chain", logger, nil, nil) require.NoError(t, err) require.NotNil(t, client) assert.NotNil(t, client.eventListener) @@ -48,27 +48,27 @@ func TestNewClient(t *testing.T) { CleanupIntervalSeconds: &cleanup, RetentionPeriodSeconds: &retention, } - client, err := NewClient(database, cfg, pc, "push-chain", logger) + client, err := NewClient(database, cfg, pc, "push-chain", logger, nil, nil) require.NoError(t, err) require.NotNil(t, client) assert.NotNil(t, client.eventCleaner) }) t.Run("nil pushcore fails", func(t *testing.T) { - _, err := NewClient(database, nil, nil, "push-chain", logger) + _, err := NewClient(database, nil, nil, "push-chain", logger, nil, nil) require.Error(t, err) assert.Contains(t, err.Error(), "push client is nil") }) t.Run("nil database fails", func(t *testing.T) { - _, err := NewClient(nil, nil, pc, "push-chain", logger) + _, err := NewClient(nil, nil, pc, "push-chain", logger, nil, nil) require.Error(t, err) assert.Contains(t, err.Error(), "database is nil") }) } func TestClient_StartStop(t *testing.T) { - client, err := NewClient(newTestDB(t), nil, newTestPushCoreClient(), "push-chain", zerolog.Nop()) + client, err := NewClient(newTestDB(t), nil, newTestPushCoreClient(), "push-chain", zerolog.Nop(), nil, nil) require.NoError(t, err) ctx := context.Background() @@ -96,7 +96,7 @@ func TestClient_StopBeforeStart(t *testing.T) { // Stop on a freshly created client (never started) should not panic. // The cancel func is nil, eventListener.Stop() returns ErrNotRunning but // the client logs and swallows that error, returning nil. - client, err := NewClient(newTestDB(t), nil, newTestPushCoreClient(), "push-chain", zerolog.Nop()) + client, err := NewClient(newTestDB(t), nil, newTestPushCoreClient(), "push-chain", zerolog.Nop(), nil, nil) require.NoError(t, err) // Should not panic or return error @@ -104,7 +104,7 @@ func TestClient_StopBeforeStart(t *testing.T) { } func TestClient_DoubleStop(t *testing.T) { - client, err := NewClient(newTestDB(t), nil, newTestPushCoreClient(), "push-chain", zerolog.Nop()) + client, err := NewClient(newTestDB(t), nil, newTestPushCoreClient(), "push-chain", zerolog.Nop(), nil, nil) require.NoError(t, err) ctx := context.Background() @@ -122,7 +122,7 @@ func TestClient_StartStopWithEventCleaner(t *testing.T) { CleanupIntervalSeconds: &cleanup, RetentionPeriodSeconds: &retention, } - client, err := NewClient(newTestDB(t), cfg, newTestPushCoreClient(), "push-chain", zerolog.Nop()) + client, err := NewClient(newTestDB(t), cfg, newTestPushCoreClient(), "push-chain", zerolog.Nop(), nil, nil) require.NoError(t, err) require.NotNil(t, client.eventCleaner) @@ -140,7 +140,7 @@ func TestClient_StartStopWithEventCleaner(t *testing.T) { func TestClient_StartStopLifecycleMultiple(t *testing.T) { // Verify the client can be started and stopped multiple times (restart). - client, err := NewClient(newTestDB(t), nil, newTestPushCoreClient(), "push-chain", zerolog.Nop()) + client, err := NewClient(newTestDB(t), nil, newTestPushCoreClient(), "push-chain", zerolog.Nop(), nil, nil) require.NoError(t, err) ctx := context.Background() @@ -183,7 +183,7 @@ func TestNewClient_CleanerAlwaysWired(t *testing.T) { } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { - client, err := NewClient(database, tc.cfg, pc, "push-chain", logger) + client, err := NewClient(database, tc.cfg, pc, "push-chain", logger, nil, nil) require.NoError(t, err) require.NotNil(t, client.eventCleaner, "cleaner must always be wired up") }) @@ -199,7 +199,7 @@ func TestNewClient_NegativePollInterval(t *testing.T) { cfg := &config.ChainSpecificConfig{ EventPollingIntervalSeconds: &poll, } - client, err := NewClient(database, cfg, pc, "push-chain", logger) + client, err := NewClient(database, cfg, pc, "push-chain", logger, nil, nil) require.NoError(t, err) // Negative poll interval should fall back to default assert.Equal(t, DefaultPollInterval, client.eventListener.cfg.PollInterval) diff --git a/universalClient/pushwatcher/event_listener.go b/universalClient/pushwatcher/event_listener.go index 7193f444..511c7ee2 100644 --- a/universalClient/pushwatcher/event_listener.go +++ b/universalClient/pushwatcher/event_listener.go @@ -28,8 +28,9 @@ type Config struct { PollInterval time.Duration } -// EventListener polls Push chain for active TSS events and pending outbounds -// via gRPC, converts them to store.Events, and inserts them into the local DB. +// EventListener polls Push chain for active TSS events, pending outbounds and +// pending read requests via gRPC, converts them to store.Events, and inserts +// them into the local DB. type EventListener struct { pushCore *pushcore.Client chainStore *common.ChainStore @@ -134,17 +135,19 @@ func (el *EventListener) run(ctx context.Context) { } } -// poll fetches pending TSS, outbound & fund migration events, stores them, and updates latest block height. +// poll fetches pending TSS, outbound, fund migration & read request events, stores them, and updates latest block height. func (el *EventListener) poll(ctx context.Context) { tssCount := el.pollTssEvents(ctx) outboundCount := el.pollOutboundEvents(ctx) migrationCount := el.pollFundMigrationEvents(ctx) + readCount := el.pollReadRequestEvents(ctx) - if total := tssCount + outboundCount + migrationCount; total > 0 { + if total := tssCount + outboundCount + migrationCount + readCount; total > 0 { el.logger.Info(). Int("tss_events", tssCount). Int("outbound_events", outboundCount). Int("migration_events", migrationCount). + Int("read_request_events", readCount). Msg("stored new events") } @@ -235,6 +238,29 @@ func (el *EventListener) pollFundMigrationEvents(ctx context.Context) int { return newCount } +// pollReadRequestEvents fetches pending external read requests and inserts +// them into the DB. Returns new event count. +func (el *EventListener) pollReadRequestEvents(ctx context.Context) int { + requests, err := el.pushCore.GetAllPendingReadRequests(ctx) + if err != nil { + el.logger.Error().Err(err).Msg("failed to fetch pending read requests") + return 0 + } + + var newCount int + for _, req := range requests { + event, err := convertReadRequestEvent(req) + if err != nil { + el.logger.Warn().Err(err).Str("request_id", req.RequestId).Msg("failed to convert read request") + continue + } + + newCount += el.storeEvent(event) + } + + return newCount +} + // storeEvent inserts an event into the DB if it doesn't already exist. // Returns 1 if stored, 0 if duplicate or error. func (el *EventListener) storeEvent(event *store.Event) int { diff --git a/universalClient/pushwatcher/event_parser.go b/universalClient/pushwatcher/event_parser.go index a2644d7d..476f7090 100644 --- a/universalClient/pushwatcher/event_parser.go +++ b/universalClient/pushwatcher/event_parser.go @@ -7,6 +7,7 @@ import ( "fmt" "github.com/pushchain/push-chain-node/universalClient/store" + ucallbacktypes "github.com/pushchain/push-chain-node/x/ucallback/types" uexecutortypes "github.com/pushchain/push-chain-node/x/uexecutor/types" utsstypes "github.com/pushchain/push-chain-node/x/utss/types" ) @@ -94,6 +95,28 @@ func convertFundMigrationEvent(migration *utsstypes.FundMigration) (*store.Event }, nil } +// convertReadRequestEvent converts a pending external read request to a store.Event. +func convertReadRequestEvent(req *ucallbacktypes.ReadRequest) (*store.Event, error) { + if req == nil || req.RequestId == "" { + return nil, fmt.Errorf("read request is nil or missing request id") + } + + eventData, err := json.Marshal(req) + if err != nil { + return nil, fmt.Errorf("failed to marshal read request event data: %w", err) + } + + return &store.Event{ + EventID: req.RequestId, // globally unique on-chain nonce; no hashing needed + BlockHeight: req.CreatedAtHeight, + ExpiryBlockHeight: req.ExpiryBlockHeight, + Type: store.EventTypeReadRequest, + ConfirmationType: store.ConfirmationInstant, + Status: store.StatusConfirmed, + EventData: eventData, + }, nil +} + // convertOutboundToEvent converts a PendingOutboundEntry + OutboundTx to a store.Event. func convertOutboundToEvent(entry *uexecutortypes.PendingOutboundEntry, outbound *uexecutortypes.OutboundTx) (*store.Event, error) { if entry == nil || outbound == nil { diff --git a/universalClient/pushwatcher/event_parser_test.go b/universalClient/pushwatcher/event_parser_test.go index cf8a98dc..fae4c123 100644 --- a/universalClient/pushwatcher/event_parser_test.go +++ b/universalClient/pushwatcher/event_parser_test.go @@ -8,6 +8,7 @@ import ( "github.com/stretchr/testify/require" "github.com/pushchain/push-chain-node/universalClient/store" + ucallbacktypes "github.com/pushchain/push-chain-node/x/ucallback/types" uexecutortypes "github.com/pushchain/push-chain-node/x/uexecutor/types" utsstypes "github.com/pushchain/push-chain-node/x/utss/types" ) @@ -397,6 +398,56 @@ func TestConvertFundMigrationEvent(t *testing.T) { }) } +func TestConvertReadRequestEvent(t *testing.T) { + t.Run("nil request returns error", func(t *testing.T) { + result, err := convertReadRequestEvent(nil) + require.Error(t, err) + assert.Nil(t, result) + assert.Contains(t, err.Error(), "read request is nil or missing request id") + }) + + t.Run("empty request id returns error", func(t *testing.T) { + result, err := convertReadRequestEvent(&ucallbacktypes.ReadRequest{RequestId: ""}) + require.Error(t, err) + assert.Nil(t, result) + assert.Contains(t, err.Error(), "read request is nil or missing request id") + }) + + t.Run("valid request converts correctly", func(t *testing.T) { + req := &ucallbacktypes.ReadRequest{ + RequestId: "0x00000000000000000000000000000000000000000000000000000000000000a1", + DestinationChain: "eip155:11155111", + Owner: []byte{0x01, 0x02}, + Query: []byte{0xde, 0xad}, + MinConfirmations: 3, + DestinationBlockHeight: 500, + ExpiryBlockHeight: 900, + CreatedAtHeight: 420, + } + + result, err := convertReadRequestEvent(req) + require.NoError(t, err) + require.NotNil(t, result) + + // EventID is the on-chain requestId verbatim (no hashing) + assert.Equal(t, req.RequestId, result.EventID) + assert.Equal(t, store.EventTypeReadRequest, result.Type) + assert.Equal(t, store.StatusConfirmed, result.Status) + assert.Equal(t, store.ConfirmationInstant, result.ConfirmationType) + assert.Equal(t, uint64(420), result.BlockHeight, "block height is the request's created-at height") + assert.Equal(t, uint64(900), result.ExpiryBlockHeight, "expiry height must be stamped for the processor's expiry check") + + // EventData round-trips back to the request + var decoded ucallbacktypes.ReadRequest + require.NoError(t, json.Unmarshal(result.EventData, &decoded)) + assert.Equal(t, req.RequestId, decoded.RequestId) + assert.Equal(t, req.DestinationChain, decoded.DestinationChain) + assert.Equal(t, req.Query, decoded.Query) + assert.Equal(t, req.MinConfirmations, decoded.MinConfirmations) + assert.Equal(t, req.DestinationBlockHeight, decoded.DestinationBlockHeight) + }) +} + func TestHashEventID(t *testing.T) { t.Run("deterministic output", func(t *testing.T) { id1 := hashEventID("keygen", "123") diff --git a/universalClient/pushwatcher/event_processor.go b/universalClient/pushwatcher/event_processor.go new file mode 100644 index 00000000..f848ae76 --- /dev/null +++ b/universalClient/pushwatcher/event_processor.go @@ -0,0 +1,151 @@ +package pushwatcher + +import ( + "context" + "sync" + "time" + + "github.com/pushchain/push-chain-node/universalClient/db" + "github.com/pushchain/push-chain-node/universalClient/externalchains/common" + "github.com/pushchain/push-chain-node/universalClient/store" + "github.com/rs/zerolog" +) + +const eventProcessBatchSize = 1000 + +// EventHandler processes one CONFIRMED push chain event of a registered type. +// Handlers own the event's status transitions; a returned error is logged and +// the event is retried next tick. +type EventHandler interface { + HandleEvent(ctx context.Context, event *store.Event) error +} + +// EventProcessor drains CONFIRMED events from the push chain DB and dispatches +// them to the handler registered for their type. Event types without a handler +// are ignored (e.g. TSS events, which are consumed by the TSS subsystem). +type EventProcessor struct { + chainStore *common.ChainStore + handlers map[string]EventHandler + cfg Config + logger zerolog.Logger + + mu sync.Mutex + running bool + cancel context.CancelFunc + wg sync.WaitGroup +} + +// NewEventProcessor creates a new push event processor. Register handlers +// before Start. +func NewEventProcessor( + database *db.DB, + pollInterval time.Duration, + logger zerolog.Logger, +) (*EventProcessor, error) { + if database == nil { + return nil, ErrNilDatabase + } + + if pollInterval <= 0 { + pollInterval = DefaultPollInterval + } + + return &EventProcessor{ + chainStore: common.NewChainStore(database), + handlers: make(map[string]EventHandler), + cfg: Config{PollInterval: pollInterval}, + logger: logger.With().Str("component", "push_event_processor").Logger(), + }, nil +} + +// RegisterHandler registers a handler for an event type. Must be called before Start. +func (p *EventProcessor) RegisterHandler(eventType string, handler EventHandler) { + p.handlers[eventType] = handler +} + +// Start begins processing events. +func (p *EventProcessor) Start(ctx context.Context) error { + p.mu.Lock() + defer p.mu.Unlock() + + if p.running { + return ErrAlreadyRunning + } + + childCtx, cancel := context.WithCancel(ctx) + p.cancel = cancel + p.running = true + + p.logger.Debug(). + Dur("poll_interval", p.cfg.PollInterval). + Msg("starting push event processor") + + p.wg.Add(1) + go p.run(childCtx) + + return nil +} + +// Stop gracefully stops the processor. +func (p *EventProcessor) Stop() error { + p.mu.Lock() + defer p.mu.Unlock() + + if !p.running { + return ErrNotRunning + } + + p.cancel() + p.wg.Wait() + p.running = false + + return nil +} + +func (p *EventProcessor) run(ctx context.Context) { + defer p.wg.Done() + + p.processConfirmedEvents(ctx) + + ticker := time.NewTicker(p.cfg.PollInterval) + defer ticker.Stop() + + for { + select { + case <-ctx.Done(): + return + case <-ticker.C: + p.processConfirmedEvents(ctx) + } + } +} + +// processConfirmedEvents dispatches CONFIRMED events to their registered handlers. +func (p *EventProcessor) processConfirmedEvents(ctx context.Context) { + events, err := p.chainStore.GetConfirmedEvents(eventProcessBatchSize) + if err != nil { + p.logger.Error().Err(err).Msg("failed to query confirmed events") + return + } + + for _, event := range events { + handler, ok := p.handlers[event.Type] + if !ok { + continue + } + + select { + case <-ctx.Done(): + return + default: + } + + if err := handler.HandleEvent(ctx, &event); err != nil { + p.logger.Error(). + Err(err). + Str("event_id", event.EventID). + Str("type", event.Type). + Msg("failed to process event") + } + } +} diff --git a/universalClient/pushwatcher/event_processor_test.go b/universalClient/pushwatcher/event_processor_test.go new file mode 100644 index 00000000..92e60bcd --- /dev/null +++ b/universalClient/pushwatcher/event_processor_test.go @@ -0,0 +1,90 @@ +package pushwatcher + +import ( + "context" + "fmt" + "testing" + + "github.com/rs/zerolog" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/pushchain/push-chain-node/universalClient/externalchains/common" + "github.com/pushchain/push-chain-node/universalClient/store" +) + +type fakeEventHandler struct { + handled []string + err error +} + +func (f *fakeEventHandler) HandleEvent(ctx context.Context, event *store.Event) error { + f.handled = append(f.handled, event.EventID) + return f.err +} + +func seedEvent(t *testing.T, cs *common.ChainStore, eventID, eventType string) { + t.Helper() + stored, err := cs.InsertEventIfNotExists(&store.Event{ + EventID: eventID, + Type: eventType, + ConfirmationType: store.ConfirmationInstant, + Status: store.StatusConfirmed, + EventData: []byte("{}"), + }) + require.NoError(t, err) + require.True(t, stored) +} + +func TestEventProcessor_DispatchesByType(t *testing.T) { + database := newTestDB(t) + p, err := NewEventProcessor(database, 0, zerolog.Nop()) + require.NoError(t, err) + cs := common.NewChainStore(database) + + readHandler := &fakeEventHandler{} + p.RegisterHandler(store.EventTypeReadRequest, readHandler) + + seedEvent(t, cs, "read-1", store.EventTypeReadRequest) + seedEvent(t, cs, "tss-1", store.EventTypeKeygen) // no handler registered + + p.processConfirmedEvents(context.Background()) + + assert.Equal(t, []string{"read-1"}, readHandler.handled) +} + +func TestEventProcessor_HandlerErrorKeepsProcessing(t *testing.T) { + database := newTestDB(t) + p, err := NewEventProcessor(database, 0, zerolog.Nop()) + require.NoError(t, err) + cs := common.NewChainStore(database) + + failing := &fakeEventHandler{err: fmt.Errorf("boom")} + p.RegisterHandler(store.EventTypeReadRequest, failing) + + seedEvent(t, cs, "read-1", store.EventTypeReadRequest) + seedEvent(t, cs, "read-2", store.EventTypeReadRequest) + + p.processConfirmedEvents(context.Background()) + + // both attempted despite errors, both still CONFIRMED for retry + assert.Len(t, failing.handled, 2) + events, err := cs.GetConfirmedEvents(10) + require.NoError(t, err) + assert.Len(t, events, 2) +} + +func TestEventProcessor_NilDatabase(t *testing.T) { + _, err := NewEventProcessor(nil, 0, zerolog.Nop()) + assert.ErrorIs(t, err, ErrNilDatabase) +} + +func TestEventProcessor_StartStop(t *testing.T) { + p, err := NewEventProcessor(newTestDB(t), 0, zerolog.Nop()) + require.NoError(t, err) + + require.NoError(t, p.Start(context.Background())) + assert.Equal(t, ErrAlreadyRunning, p.Start(context.Background())) + require.NoError(t, p.Stop()) + assert.Equal(t, ErrNotRunning, p.Stop()) +} diff --git a/universalClient/pushwatcher/read_event_processor.go b/universalClient/pushwatcher/read_event_processor.go new file mode 100644 index 00000000..9adbb135 --- /dev/null +++ b/universalClient/pushwatcher/read_event_processor.go @@ -0,0 +1,150 @@ +package pushwatcher + +import ( + "context" + "encoding/json" + "fmt" + "strings" + + "github.com/pushchain/push-chain-node/universalClient/db" + "github.com/pushchain/push-chain-node/universalClient/externalchains/common" + "github.com/pushchain/push-chain-node/universalClient/externalchains/web2" + "github.com/pushchain/push-chain-node/universalClient/store" + ucallbacktypes "github.com/pushchain/push-chain-node/x/ucallback/types" + "github.com/rs/zerolog" +) + +// ChainResolver resolves a CAIP-2 chain ID to its chain client. +// Satisfied by externalchains.Chains. +type ChainResolver interface { + GetClient(chainID string) (common.ChainClient, error) +} + +// readVoter submits a read observation vote to Push Chain. +// Satisfied by *pushsigner.Signer. +type readVoter interface { + VoteReadResult(ctx context.Context, requestID string, result *ucallbacktypes.ReadResult) (string, error) +} + +// ReadEventProcessor handles READ_REQUEST events: it executes each request on +// its destination chain via the resolved read handler and votes the result. +// Transient failures (destination not served, RPC errors, vote failure) keep +// the event CONFIRMED for retry; corrupt events flip to REVERTED. Expiry is +// core's job: expired requests leave the pending query. +type ReadEventProcessor struct { + voter readVoter + resolver ChainResolver + web2Handler common.ReadRequestHandler + chainStore *common.ChainStore + logger zerolog.Logger +} + +// NewReadEventProcessor creates the handler for READ_REQUEST events. +// web2Handler serves web2 destinations; nil means web2 reads are not served. +func NewReadEventProcessor( + voter readVoter, + resolver ChainResolver, + web2Handler common.ReadRequestHandler, + database *db.DB, + logger zerolog.Logger, +) (*ReadEventProcessor, error) { + if database == nil { + return nil, ErrNilDatabase + } + + return &ReadEventProcessor{ + voter: voter, + resolver: resolver, + web2Handler: web2Handler, + chainStore: common.NewChainStore(database), + logger: logger.With().Str("component", "push_read_event_processor").Logger(), + }, nil +} + +// HandleEvent implements EventHandler for READ_REQUEST events. +func (p *ReadEventProcessor) HandleEvent(ctx context.Context, event *store.Event) error { + if p.isExpired(event) { + p.logger.Info().Str("event_id", event.EventID).Msg("read request expired; marking reverted") + p.markReverted(event.EventID) + return nil + } + + var req ucallbacktypes.ReadRequest + if err := json.Unmarshal(event.EventData, &req); err != nil { + p.markReverted(event.EventID) + return err + } + + log := p.logger.With().Str("request_id", req.RequestId).Logger() + + handler, err := p.resolveHandler(req.DestinationChain) + if err != nil { + // destination not served by this validator yet; retry next tick + log.Debug().Err(err).Str("destination_chain", req.DestinationChain).Msg("destination not served") + return nil + } + + result, err := handler.ExecuteRead(ctx, &req) + if err != nil { + log.Debug().Err(err).Str("destination_chain", req.DestinationChain).Msg("read execution failed; will retry") + return nil + } + + voteTxHash, err := p.voter.VoteReadResult(ctx, req.RequestId, result) + if err != nil { + log.Warn().Err(err).Msg("failed to vote read result; will retry") + return nil + } + + rowsAffected, err := p.chainStore.UpdateStatusAndVoteTxHash(event.EventID, store.StatusConfirmed, store.StatusCompleted, voteTxHash) + if err != nil { + return err + } + if rowsAffected == 0 { + return nil + } + + log.Info(). + Str("vote_tx_hash", voteTxHash). + Int32("status", int32(result.Status)). + Str("error_code", result.ErrorCode.String()). + Msg("read request voted") + + return nil +} + +// resolveHandler returns the read handler for a destination: the web2 executor +// for web2 destinations, otherwise the destination chain client's handler. +func (p *ReadEventProcessor) resolveHandler(destination string) (common.ReadRequestHandler, error) { + if strings.HasPrefix(destination, web2.DestinationPrefix) { + if p.web2Handler == nil { + return nil, fmt.Errorf("web2 reads not served") + } + return p.web2Handler, nil + } + + destClient, err := p.resolver.GetClient(destination) + if err != nil { + return nil, err + } + return destClient.GetReadRequestHandler() +} + +// isExpired reports whether the request's expiry Push chain height has been +// reached, using the chain height persisted by the event listener. +func (p *ReadEventProcessor) isExpired(event *store.Event) bool { + if event.ExpiryBlockHeight == 0 { + return false + } + pushHeight, err := p.chainStore.GetChainHeight() + if err != nil { + return false + } + return pushHeight >= event.ExpiryBlockHeight +} + +func (p *ReadEventProcessor) markReverted(eventID string) { + if _, err := p.chainStore.UpdateEventStatus(eventID, store.StatusConfirmed, store.StatusReverted); err != nil { + p.logger.Error().Err(err).Str("event_id", eventID).Msg("failed to mark read request reverted") + } +} diff --git a/universalClient/pushwatcher/read_event_processor_test.go b/universalClient/pushwatcher/read_event_processor_test.go new file mode 100644 index 00000000..73d60dcf --- /dev/null +++ b/universalClient/pushwatcher/read_event_processor_test.go @@ -0,0 +1,250 @@ +package pushwatcher + +import ( + "context" + "fmt" + "testing" + + "github.com/rs/zerolog" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/pushchain/push-chain-node/universalClient/externalchains/common" + "github.com/pushchain/push-chain-node/universalClient/store" + ucallbacktypes "github.com/pushchain/push-chain-node/x/ucallback/types" +) + +type fakeReadVoter struct { + votes map[string]*ucallbacktypes.ReadResult + txHash string + err error +} + +func (f *fakeReadVoter) VoteReadResult(ctx context.Context, requestID string, result *ucallbacktypes.ReadResult) (string, error) { + if f.err != nil { + return "", f.err + } + if f.votes == nil { + f.votes = make(map[string]*ucallbacktypes.ReadResult) + } + f.votes[requestID] = result + return f.txHash, nil +} + +type fakeDestClient struct { + result *ucallbacktypes.ReadResult + err error + notStarted bool +} + +func (f *fakeDestClient) Start(ctx context.Context) error { return nil } +func (f *fakeDestClient) Stop() error { return nil } +func (f *fakeDestClient) IsHealthy() bool { return true } +func (f *fakeDestClient) GetTxBuilder() (common.TxBuilder, error) { + return nil, fmt.Errorf("not supported") +} +func (f *fakeDestClient) GetReadRequestHandler() (common.ReadRequestHandler, error) { + if f.notStarted { + return nil, fmt.Errorf("client not started") + } + return f, nil +} +func (f *fakeDestClient) ExecuteRead(ctx context.Context, req *ucallbacktypes.ReadRequest) (*ucallbacktypes.ReadResult, error) { + return f.result, f.err +} + +type fakeChainResolver struct { + client common.ChainClient +} + +func (f *fakeChainResolver) GetClient(chainID string) (common.ChainClient, error) { + if f.client == nil { + return nil, fmt.Errorf("no client for %s", chainID) + } + return f.client, nil +} + +func testReadRequest() *ucallbacktypes.ReadRequest { + return &ucallbacktypes.ReadRequest{ + RequestId: "0xabc123", + DestinationChain: "eip155:11155111", + Query: []byte{0x01}, + MinConfirmations: 1, + DestinationBlockHeight: 100, + CreatedAtHeight: 7, + } +} + +func newTestReadEventProcessor(t *testing.T, voter readVoter, destClient common.ChainClient) (*ReadEventProcessor, *common.ChainStore) { + t.Helper() + database := newTestDB(t) + p, err := NewReadEventProcessor(voter, &fakeChainResolver{client: destClient}, nil, database, zerolog.Nop()) + require.NoError(t, err) + return p, common.NewChainStore(database) +} + +func seedReadRequest(t *testing.T, cs *common.ChainStore, req *ucallbacktypes.ReadRequest) *store.Event { + t.Helper() + event, err := convertReadRequestEvent(req) + require.NoError(t, err) + stored, err := cs.InsertEventIfNotExists(event) + require.NoError(t, err) + require.True(t, stored) + return event +} + +func assertStatus(t *testing.T, cs *common.ChainStore, eventID, status string) { + t.Helper() + rows, err := cs.UpdateEventStatus(eventID, status, status) + require.NoError(t, err) + assert.Equal(t, int64(1), rows, "event %s not in status %s", eventID, status) +} + +func TestReadEventProcessor_SuccessFlow(t *testing.T) { + req := testReadRequest() + result := &ucallbacktypes.ReadResult{ + Status: ucallbacktypes.ReadStatus_READ_STATUS_SUCCESS, + ResultData: []byte{0xaa}, + } + voter := &fakeReadVoter{txHash: "VOTE_TX"} + p, cs := newTestReadEventProcessor(t, voter, &fakeDestClient{result: result}) + event := seedReadRequest(t, cs, req) + + require.NoError(t, p.HandleEvent(context.Background(), event)) + + require.Contains(t, voter.votes, req.RequestId) + assert.Equal(t, result, voter.votes[req.RequestId]) + assertStatus(t, cs, event.EventID, store.StatusCompleted) +} + +func TestReadEventProcessor_VoteFailureKeepsConfirmed(t *testing.T) { + req := testReadRequest() + voter := &fakeReadVoter{err: fmt.Errorf("MsgVoteReadResult not available")} + p, cs := newTestReadEventProcessor(t, voter, &fakeDestClient{result: &ucallbacktypes.ReadResult{Status: ucallbacktypes.ReadStatus_READ_STATUS_SUCCESS}}) + event := seedReadRequest(t, cs, req) + + require.NoError(t, p.HandleEvent(context.Background(), event)) + + assertStatus(t, cs, event.EventID, store.StatusConfirmed) +} + +func TestReadEventProcessor_ExecutionFailureRetries(t *testing.T) { + req := testReadRequest() + voter := &fakeReadVoter{txHash: "VOTE_TX"} + p, cs := newTestReadEventProcessor(t, voter, &fakeDestClient{err: fmt.Errorf("rpc down")}) + event := seedReadRequest(t, cs, req) + + require.NoError(t, p.HandleEvent(context.Background(), event)) + + assert.Empty(t, voter.votes) + assertStatus(t, cs, event.EventID, store.StatusConfirmed) +} + +func TestReadEventProcessor_UnservedChainRetries(t *testing.T) { + req := testReadRequest() + voter := &fakeReadVoter{txHash: "VOTE_TX"} + p, cs := newTestReadEventProcessor(t, voter, nil) + event := seedReadRequest(t, cs, req) + + require.NoError(t, p.HandleEvent(context.Background(), event)) + + assert.Empty(t, voter.votes) + assertStatus(t, cs, event.EventID, store.StatusConfirmed) +} + +func TestReadEventProcessor_HandlerUnavailableRetries(t *testing.T) { + req := testReadRequest() + voter := &fakeReadVoter{txHash: "VOTE_TX"} + p, cs := newTestReadEventProcessor(t, voter, &fakeDestClient{notStarted: true}) + event := seedReadRequest(t, cs, req) + + require.NoError(t, p.HandleEvent(context.Background(), event)) + + assert.Empty(t, voter.votes) + assertStatus(t, cs, event.EventID, store.StatusConfirmed) +} + +func TestReadEventProcessor_CorruptEventReverted(t *testing.T) { + voter := &fakeReadVoter{txHash: "VOTE_TX"} + p, cs := newTestReadEventProcessor(t, voter, &fakeDestClient{result: &ucallbacktypes.ReadResult{Status: ucallbacktypes.ReadStatus_READ_STATUS_SUCCESS}}) + + event := &store.Event{ + EventID: "corrupt-read", + Type: store.EventTypeReadRequest, + ConfirmationType: store.ConfirmationInstant, + Status: store.StatusConfirmed, + EventData: []byte("not json"), + } + stored, err := cs.InsertEventIfNotExists(event) + require.NoError(t, err) + require.True(t, stored) + + require.Error(t, p.HandleEvent(context.Background(), event)) + + assert.Empty(t, voter.votes) + assertStatus(t, cs, event.EventID, store.StatusReverted) +} + +func TestReadEventProcessor_ExpiredMarkedReverted(t *testing.T) { + req := testReadRequest() + req.ExpiryBlockHeight = 50 + voter := &fakeReadVoter{txHash: "VOTE_TX"} + p, cs := newTestReadEventProcessor(t, voter, &fakeDestClient{result: &ucallbacktypes.ReadResult{Status: ucallbacktypes.ReadStatus_READ_STATUS_SUCCESS}}) + require.NoError(t, cs.UpdateChainHeight(100)) // push chain past expiry + event := seedReadRequest(t, cs, req) + + require.NoError(t, p.HandleEvent(context.Background(), event)) + + assert.Empty(t, voter.votes) + assertStatus(t, cs, event.EventID, store.StatusReverted) +} + +func TestReadEventProcessor_NotExpiredProcessesNormally(t *testing.T) { + req := testReadRequest() + req.ExpiryBlockHeight = 200 + voter := &fakeReadVoter{txHash: "VOTE_TX"} + p, cs := newTestReadEventProcessor(t, voter, &fakeDestClient{result: &ucallbacktypes.ReadResult{Status: ucallbacktypes.ReadStatus_READ_STATUS_SUCCESS}}) + require.NoError(t, cs.UpdateChainHeight(100)) + event := seedReadRequest(t, cs, req) + + require.NoError(t, p.HandleEvent(context.Background(), event)) + + require.Contains(t, voter.votes, req.RequestId) + assertStatus(t, cs, event.EventID, store.StatusCompleted) +} + +func TestReadEventProcessor_Web2Dispatch(t *testing.T) { + req := testReadRequest() + req.DestinationChain = "web2:https" + result := &ucallbacktypes.ReadResult{Status: ucallbacktypes.ReadStatus_READ_STATUS_SUCCESS, ResultData: []byte{0xbb}} + + t.Run("dispatches to web2 handler", func(t *testing.T) { + database := newTestDB(t) + voter := &fakeReadVoter{txHash: "VOTE_TX"} + web2Handler := &fakeDestClient{result: result} + p, err := NewReadEventProcessor(voter, &fakeChainResolver{}, web2Handler, database, zerolog.Nop()) + require.NoError(t, err) + cs := common.NewChainStore(database) + event := seedReadRequest(t, cs, req) + + require.NoError(t, p.HandleEvent(context.Background(), event)) + + require.Contains(t, voter.votes, req.RequestId) + assert.Equal(t, result, voter.votes[req.RequestId]) + assertStatus(t, cs, event.EventID, store.StatusCompleted) + }) + + t.Run("no web2 handler retries", func(t *testing.T) { + database := newTestDB(t) + voter := &fakeReadVoter{txHash: "VOTE_TX"} + p, err := NewReadEventProcessor(voter, &fakeChainResolver{}, nil, database, zerolog.Nop()) + require.NoError(t, err) + cs := common.NewChainStore(database) + event := seedReadRequest(t, cs, req) + + require.NoError(t, p.HandleEvent(context.Background(), event)) + + assert.Empty(t, voter.votes) + assertStatus(t, cs, event.EventID, store.StatusConfirmed) + }) +} diff --git a/universalClient/store/models.go b/universalClient/store/models.go index 98ef87d8..b3cc331b 100644 --- a/universalClient/store/models.go +++ b/universalClient/store/models.go @@ -28,6 +28,7 @@ const ( EventTypeSignFundMigrate = "SIGN_FUND_MIGRATE" EventTypeInbound = "INBOUND" EventTypeOutbound = "OUTBOUND" + EventTypeReadRequest = "READ_REQUEST" ) // Confirmation type values. diff --git a/universalClient/tss/coordinator/coordinator_test.go b/universalClient/tss/coordinator/coordinator_test.go index 69cf0f26..b4ea3cd4 100644 --- a/universalClient/tss/coordinator/coordinator_test.go +++ b/universalClient/tss/coordinator/coordinator_test.go @@ -84,6 +84,9 @@ type coordMockChainClient struct { func (m *coordMockChainClient) Start(context.Context) error { return nil } func (m *coordMockChainClient) Stop() error { return nil } func (m *coordMockChainClient) IsHealthy() bool { return true } +func (m *coordMockChainClient) GetReadRequestHandler() (common.ReadRequestHandler, error) { + return nil, nil +} func (m *coordMockChainClient) GetTxBuilder() (common.TxBuilder, error) { if m.builderErr != nil { return nil, m.builderErr diff --git a/universalClient/tss/txbroadcaster/broadcaster_test.go b/universalClient/tss/txbroadcaster/broadcaster_test.go index 653d13d0..dae85fb3 100644 --- a/universalClient/tss/txbroadcaster/broadcaster_test.go +++ b/universalClient/tss/txbroadcaster/broadcaster_test.go @@ -79,9 +79,12 @@ func (m *mockTxBuilder) BroadcastFundMigrationTx(ctx context.Context, req *commo type mockChainClient struct{ builder *mockTxBuilder } -func (m *mockChainClient) Start(context.Context) error { return nil } -func (m *mockChainClient) Stop() error { return nil } -func (m *mockChainClient) IsHealthy() bool { return true } +func (m *mockChainClient) Start(context.Context) error { return nil } +func (m *mockChainClient) Stop() error { return nil } +func (m *mockChainClient) IsHealthy() bool { return true } +func (m *mockChainClient) GetReadRequestHandler() (common.ReadRequestHandler, error) { + return nil, nil +} func (m *mockChainClient) GetTxBuilder() (common.TxBuilder, error) { return m.builder, nil } func setupTestDB(t *testing.T) (*eventstore.Store, *gorm.DB) { diff --git a/universalClient/tss/txresolver/resolver_test.go b/universalClient/tss/txresolver/resolver_test.go index b7df913f..b13aec47 100644 --- a/universalClient/tss/txresolver/resolver_test.go +++ b/universalClient/tss/txresolver/resolver_test.go @@ -76,9 +76,12 @@ func (m *mockTxBuilder) BroadcastFundMigrationTx(ctx context.Context, req *commo type mockChainClient struct{ builder *mockTxBuilder } -func (m *mockChainClient) Start(context.Context) error { return nil } -func (m *mockChainClient) Stop() error { return nil } -func (m *mockChainClient) IsHealthy() bool { return true } +func (m *mockChainClient) Start(context.Context) error { return nil } +func (m *mockChainClient) Stop() error { return nil } +func (m *mockChainClient) IsHealthy() bool { return true } +func (m *mockChainClient) GetReadRequestHandler() (common.ReadRequestHandler, error) { + return nil, nil +} func (m *mockChainClient) GetTxBuilder() (common.TxBuilder, error) { return m.builder, nil } func setupTestDB(t *testing.T) (*eventstore.Store, *gorm.DB) { diff --git a/x/ucallback/README.md b/x/ucallback/README.md new file mode 100755 index 00000000..17c8d110 --- /dev/null +++ b/x/ucallback/README.md @@ -0,0 +1,3 @@ +# Example Module + +This is a module base generated with [`spawn`](https://github.com/rollchains/spawn). \ No newline at end of file diff --git a/x/ucallback/autocli.go b/x/ucallback/autocli.go new file mode 100755 index 00000000..354c64e3 --- /dev/null +++ b/x/ucallback/autocli.go @@ -0,0 +1,67 @@ +package module + +import ( + autocliv1 "cosmossdk.io/api/cosmos/autocli/v1" + modulev1 "github.com/pushchain/push-chain-node/api/ucallback/v1" +) + +// AutoCLIOptions implements the autocli.HasAutoCLIConfig interface. +func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions { + return &autocliv1.ModuleOptions{ + Query: &autocliv1.ServiceCommandDescriptor{ + Service: modulev1.Query_ServiceDesc.ServiceName, + RpcCommandOptions: []*autocliv1.RpcCommandOptions{ + { + RpcMethod: "Params", + Use: "params", + Short: "Query the current consensus parameters", + }, + { + RpcMethod: "AllPendingReadRequests", + Use: "pending-read-requests", + Short: "List read requests awaiting an observation", + }, + { + RpcMethod: "UniversalRead", + Use: "universal-read ", + Short: "Query one read request by id", + PositionalArgs: []*autocliv1.PositionalArgDescriptor{{ProtoField: "request_id"}}, + }, + { + RpcMethod: "AllAbortedReadRequests", + Use: "aborted-read-requests", + Short: "List reads the chain gave up on; these need manual intervention", + }, + { + RpcMethod: "ReadsByTx", + Use: "reads-by-tx ", + Short: "List every read requested by one Push transaction", + PositionalArgs: []*autocliv1.PositionalArgDescriptor{{ProtoField: "tx_hash"}}, + }, + }, + }, + Tx: &autocliv1.ServiceCommandDescriptor{ + Service: modulev1.Msg_ServiceDesc.ServiceName, + RpcCommandOptions: []*autocliv1.RpcCommandOptions{ + { + RpcMethod: "UpdateParams", + Skip: false, // set to true if authority gated + }, + { + RpcMethod: "RetryReadExpiry", + Use: "retry-read-expiry ", + Short: "Admin: reattempt expiry for an abandoned read", + PositionalArgs: []*autocliv1.PositionalArgDescriptor{{ProtoField: "request_id"}}, + }, + { + RpcMethod: "VoteReadResult", + Use: "vote-read-result ", + Short: "Vote on the observed outcome of a read request", + PositionalArgs: []*autocliv1.PositionalArgDescriptor{ + {ProtoField: "request_id"}, + }, + }, + }, + }, + } +} diff --git a/x/ucallback/client/cli/query.go b/x/ucallback/client/cli/query.go new file mode 100755 index 00000000..3ac724db --- /dev/null +++ b/x/ucallback/client/cli/query.go @@ -0,0 +1,50 @@ +package cli + +import ( + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + + "github.com/pushchain/push-chain-node/x/ucallback/types" +) + +// !NOTE: Must enable in module.go (disabled in favor of autocli.go) + +func GetQueryCmd() *cobra.Command { + queryCmd := &cobra.Command{ + Use: types.ModuleName, + Short: "Querying commands for " + types.ModuleName, + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + queryCmd.AddCommand( + GetCmdParams(), + ) + return queryCmd +} + +func GetCmdParams() *cobra.Command { + cmd := &cobra.Command{ + Use: "params", + Short: "Show all module params", + Args: cobra.ExactArgs(0), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + + queryClient := types.NewQueryClient(clientCtx) + res, err := queryClient.Params(cmd.Context(), &types.QueryParamsRequest{}) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + flags.AddQueryFlagsToCmd(cmd) + return cmd +} diff --git a/x/ucallback/client/cli/tx.go b/x/ucallback/client/cli/tx.go new file mode 100755 index 00000000..6cdf69fd --- /dev/null +++ b/x/ucallback/client/cli/tx.go @@ -0,0 +1,71 @@ +package cli + +import ( + "strconv" + + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/client/tx" + + "github.com/pushchain/push-chain-node/x/ucallback/types" +) + +// !NOTE: Must enable in module.go (disabled in favor of autocli.go) + +// NewTxCmd returns a root CLI command handler for certain modules +// transaction commands. +func NewTxCmd() *cobra.Command { + txCmd := &cobra.Command{ + Use: types.ModuleName, + Short: types.ModuleName + " subcommands.", + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + + txCmd.AddCommand( + MsgUpdateParams(), + ) + return txCmd +} + +// Returns a CLI command handler for registering a +// contract for the module. +func MsgUpdateParams() *cobra.Command { + cmd := &cobra.Command{ + Use: "update-params [some-value]", + Short: "Update the params (must be submitted from the authority)", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + cliCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + senderAddress := cliCtx.GetFromAddress() + + someValue, err := strconv.ParseBool(args[0]) + if err != nil { + return err + } + + msg := &types.MsgUpdateParams{ + Authority: senderAddress.String(), + Params: types.Params{ + SomeValue: someValue, + }, + } + + if err := msg.Validate(); err != nil { + return err + } + + return tx.GenerateOrBroadcastTxCLI(cliCtx, cmd.Flags(), msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + return cmd +} diff --git a/x/ucallback/depinject.go b/x/ucallback/depinject.go new file mode 100755 index 00000000..f0b90dea --- /dev/null +++ b/x/ucallback/depinject.go @@ -0,0 +1,70 @@ +package module + +import ( + "os" + + "github.com/cosmos/cosmos-sdk/codec" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + slashingkeeper "github.com/cosmos/cosmos-sdk/x/slashing/keeper" + + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" + + "cosmossdk.io/core/address" + "cosmossdk.io/core/appmodule" + "cosmossdk.io/core/store" + "cosmossdk.io/depinject" + "cosmossdk.io/log" + + modulev1 "github.com/pushchain/push-chain-node/api/ucallback/module/v1" + "github.com/pushchain/push-chain-node/x/ucallback/keeper" + "github.com/pushchain/push-chain-node/x/ucallback/types" +) + +var _ appmodule.AppModule = AppModule{} + +// IsOnePerModuleType implements the depinject.OnePerModuleType interface. +func (am AppModule) IsOnePerModuleType() {} + +// IsAppModule implements the appmodule.AppModule interface. +func (am AppModule) IsAppModule() {} + +func init() { + appmodule.Register( + &modulev1.Module{}, + appmodule.Provide(ProvideModule), + ) +} + +type ModuleInputs struct { + depinject.In + + Cdc codec.Codec + StoreService store.KVStoreService + AddressCodec address.Codec + + StakingKeeper stakingkeeper.Keeper + SlashingKeeper slashingkeeper.Keeper + + UvalidatorKeeper types.UValidatorKeeper + EVMKeeper types.EVMKeeper + AccountKeeper types.AccountKeeper + BankKeeper types.BankKeeper + FeeMarketKeeper types.FeeMarketKeeper +} + +type ModuleOutputs struct { + depinject.Out + + Module appmodule.AppModule + Keeper keeper.Keeper +} + +func ProvideModule(in ModuleInputs) ModuleOutputs { + govAddr := authtypes.NewModuleAddress(govtypes.ModuleName).String() + + k := keeper.NewKeeper(in.Cdc, in.StoreService, log.NewLogger(os.Stderr), govAddr, in.UvalidatorKeeper, in.EVMKeeper, in.AccountKeeper, in.BankKeeper, in.FeeMarketKeeper) + m := NewAppModule(in.Cdc, k) + + return ModuleOutputs{Module: m, Keeper: k, Out: depinject.Out{}} +} diff --git a/x/ucallback/keeper/ballot_hooks.go b/x/ucallback/keeper/ballot_hooks.go new file mode 100644 index 00000000..54d64272 --- /dev/null +++ b/x/ucallback/keeper/ballot_hooks.go @@ -0,0 +1,243 @@ +package keeper + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + evmtypes "github.com/cosmos/evm/x/vm/types" + + "github.com/pushchain/push-chain-node/x/ucallback/types" + uvalidatortypes "github.com/pushchain/push-chain-node/x/uvalidator/types" +) + +// BallotHooks reacts to READ_RESULT ballots reaching a terminal state. +// +// Fulfilment is driven from here rather than from the vote that reached quorum, so +// it happens exactly once regardless of which validator's vote was decisive. Doing +// it in VoteReadResult would make the deciding validator pay the callback's gas and +// would tie the EVM call's success to that one transaction. +type BallotHooks struct { + k Keeper +} + +// NewBallotHooks returns the ballot hook implementation for x/ucallback. +func NewBallotHooks(k Keeper) uvalidatortypes.BallotHooks { + return BallotHooks{k: k} +} + +var _ uvalidatortypes.BallotHooks = BallotHooks{} + +// AfterBallotTerminal dispatches on ballot type, ignoring everything that is not a +// read result — x/uexecutor owns the other kinds. +func (h BallotHooks) AfterBallotTerminal( + ctx sdk.Context, + ballotID string, + ballotType uvalidatortypes.BallotObservationType, + status uvalidatortypes.BallotStatus, +) error { + if ballotType != uvalidatortypes.BallotObservationType_BALLOT_OBSERVATION_TYPE_READ_RESULT { + return nil + } + return h.afterReadBallotTerminal(ctx, ballotID, status) +} + +// afterReadBallotTerminal settles the read the ballot belongs to. +// +// Per the BallotHooks contract this must be idempotent and must not block the +// terminal transition. Every branch below that cannot make progress logs and +// returns nil; only a genuine state-write failure propagates. +func (h BallotHooks) afterReadBallotTerminal( + ctx sdk.Context, + ballotID string, + status uvalidatortypes.BallotStatus, +) error { + ur, found := h.k.GetUniversalReadByBallot(ctx, ballotID) + if !found { + // The lookup scans in-flight reads only, so a miss means the request has + // already settled — this hook re-firing, or a ballot that is not ours. + // Either way there is nothing left to do. + h.k.Logger().Debug("read ballot terminal: no in-flight request owns it", + "ballot_id", ballotID, "status", status.String()) + return nil + } + + if status != uvalidatortypes.BallotStatus_BALLOT_STATUS_PASSED { + // EXPIRED or REJECTED — neither retires the request here. + // + // Expiry belongs to the sweeper, not to this hook. A request's deadline is a + // property of the request, and PendingByExpiry already tracks it directly; + // an expiring ballot is only a shadow of that. Worse, ballot expiry is lazy + // — x/uvalidator runs ExpireBallotsBeforeHeight from inside CreateBallot, + // with no EndBlocker — so this hook fires only when some unrelated ballot + // happens to be created. The sweeper covers strictly more (requests nobody + // ever voted on have no ballot at all) and, running every block, never + // later. A second path here would add a race and buy nothing. + // + // REJECTED is not a deadline either: the request keeps its remaining time + // and another observation may still win. + h.k.Logger().Debug("read ballot did not pass, leaving request to the sweeper", + "ballot_id", ballotID, "request_id", ur.Id, "status", status.String()) + return nil + } + + if ur.Result == nil { + // A PASSED ballot always has its observation attached by VoteReadResult. + // Reaching here means the two disagree, which we cannot repair from the + // ballot alone — the ballot ID is a digest, not the observation. + h.k.Logger().Error("read ballot passed with no recorded result", + "ballot_id", ballotID, "request_id", ur.Id) + return nil + } + + return h.k.FulfilRead(ctx, ur) +} + +// FulfilRead delivers a settled observation to UniversalCallback and records the +// outcome on the request. +// +// The read is only marked terminal when the contract actually settled it. That +// distinction matters: on any revert the whole transaction rolls back, so +// fulfilledRequests stays false, _pending survives and _settle never runs — the +// funder's deposit is still escrowed. Retiring the record in that state would drop +// it out of PendingByExpiry, leaving nothing able to release those funds, since +// expireExternalRead admits only this module. +// +// A reverting app callback is NOT such a case: the contract catches it with .call, +// so the outer transaction succeeds, the request settles, and we mark it FULFILLED. +func (k Keeper) FulfilRead(ctx sdk.Context, ur types.UniversalRead) error { + _, moduleHex := k.GetModuleAddress(ctx) + + // A request that did not fund the gas it declared is never executed. Running it + // on a short budget would hand the app less gas than it asked for, which fails + // anyway and charges the funder for a doomed attempt. Left in flight instead, so + // the sweeper expires it at its deadline and the whole budget goes back. + affordable, err := k.CanAffordCallback(ctx, ur.Request) + if err != nil { + return err + } + if !affordable { + ur.ErrorMsg = ErrBudgetTooSmall + k.Logger().Warn("read not fulfilled: callback budget too small", + "request_id", ur.Id, + "callback_gas_limit", ur.Request.GetCallbackGasLimit(), + "callback_budget", ur.Request.GetCallbackBudget()) + return k.SetUniversalRead(ctx, ur) + } + + tmpCtx, commit := ctx.CacheContext() + res, callErr := k.CallFulfillExternalCallback(tmpCtx, ur.Id, ur.Result) + + var vmErr string + var revertData []byte + if res != nil { + vmErr, revertData = res.VmError, res.Ret + } + outcome := types.ClassifyCall(vmErr, revertData, callErr) + + if outcome == types.CallOK { + commit() + } + + ur.PcTx = append(ur.PcTx, pcTxFrom(ctx, moduleHex, res, callErr)) + + switch outcome { + case types.CallOK: + ur.Status = types.UniversalReadStatus_UNIVERSAL_READ_STATUS_FULFILLED + k.Logger().Info("read request fulfilled", + "request_id", ur.Id, "tx_hash", pcTxHash(res)) + + // Settle: tell the contract what the callback cost, then destroy exactly + // that. Ordered report-then-take because reportCallbackGas releases the + // refund and decrements totalEscrowed first — taking beforehand would leave + // the contract briefly holding less than it owes. + if err := k.settleCallbackGas(ctx, &ur, res); err != nil { + // The callback ran and the contract is EXECUTED; only the accounting + // failed. Record it and leave the status terminal — re-running fulfil + // would revert, and the escrow is recoverable by admin. + ur.ErrorMsg = err.Error() + k.Logger().Error("callback gas not settled", + "request_id", ur.Id, "error", err.Error()) + } + + case types.CallAlreadySettled: + // The contract closed it another way and the funder already has their + // refund. Terminal, but not a fulfilment we performed. + ur.Status = types.UniversalReadStatus_UNIVERSAL_READ_STATUS_FAILED + ur.ErrorMsg = pcTxError(res, callErr) + k.Logger().Warn("read already settled on the contract", + "request_id", ur.Id, "error", ur.ErrorMsg) + + default: + // CallOutOfGas or CallUnsettled. Nothing persisted, so the request stays in + // flight and PendingByExpiry keeps it — the sweeper will expire it at its + // deadline and the funder gets refunded. Status is deliberately untouched. + ur.ErrorMsg = pcTxError(res, callErr) + k.Logger().Error("read fulfilment did not settle; leaving in flight for expiry", + "request_id", ur.Id, "outcome", outcome.String(), "error", ur.ErrorMsg) + } + + return k.SetUniversalRead(ctx, ur) +} + +// Concrete pointer types, not interfaces: a nil *MsgEthereumTxResponse boxed into +// an interface is not itself nil, so the guards below would not fire. +func pcTxHash(res *evmtypes.MsgEthereumTxResponse) string { + if res == nil { + return "" + } + return res.Hash +} + +// pcTxError picks the reason worth storing on-chain. res.VmError comes first +// because a revert produces both a response and an error, and the error is the +// wrapper's decoration (": ret 0x...") around the same fact. The bare VM +// reason is the stable one; callErr is only informative when there is no response. +func pcTxError(res *evmtypes.MsgEthereumTxResponse, callErr error) string { + if res != nil && res.VmError != "" { + return res.VmError + } + if callErr != nil { + return callErr.Error() + } + return "unknown" +} + +// settleCallbackGas reports the callback's cost and burns what the contract clamps +// it to. +// +// The burn amount is recomputed here rather than read back from the EVM return +// data: with the affordability gate in place the clamp can never bind, so the two +// agree, and min() keeps that true even if the gate is ever relaxed. +func (k Keeper) settleCallbackGas( + ctx sdk.Context, ur *types.UniversalRead, res *evmtypes.MsgEthereumTxResponse, +) error { + if res == nil { + return fmt.Errorf("no receipt to price the callback from") + } + + cost, err := k.CallbackCost(ctx, res.GasUsed) + if err != nil { + return err + } + budget, err := parseBudget(ur.Request.GetCallbackBudget()) + if err != nil { + return err + } + if cost.Cmp(budget) > 0 { + cost = budget + } + + _, moduleHex := k.GetModuleAddress(ctx) + repRes, repErr := k.CallReportCallbackGas(ctx, ur.Id, cost) + ur.PcTx = append(ur.PcTx, pcTxFrom(ctx, moduleHex, repRes, repErr)) + + var vmErr string + if repRes != nil { + vmErr = repRes.VmError + } + if repErr != nil || vmErr != "" { + return fmt.Errorf("reportCallbackGas failed: %s", pcTxError(repRes, repErr)) + } + + return k.TakeAndBurn(ctx, cost) +} diff --git a/x/ucallback/keeper/ballot_hooks_test.go b/x/ucallback/keeper/ballot_hooks_test.go new file mode 100644 index 00000000..7de14f6b --- /dev/null +++ b/x/ucallback/keeper/ballot_hooks_test.go @@ -0,0 +1,333 @@ +package keeper_test + +import ( + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/crypto" + + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + "github.com/ethereum/go-ethereum/common" + + "github.com/stretchr/testify/require" + + "github.com/pushchain/push-chain-node/x/ucallback/keeper" + "github.com/pushchain/push-chain-node/x/ucallback/types" + uvalidatortypes "github.com/pushchain/push-chain-node/x/uvalidator/types" +) + +// moduleEVMAddr is the address UniversalCallback admits as caller. +func moduleEVMAddr() common.Address { + var a common.Address + copy(a[:], authtypes.NewModuleAddress(types.ModuleName).Bytes()) + return a +} + +// voteToQuorum drives a request to a finalized ballot and returns its key. +func voteToQuorum(t *testing.T, f *testFixture, id string, r *types.ReadResult) string { + t.Helper() + v := seedVoters(t, f, 4) + for i := 0; i < 3; i++ { + if _, err := f.k.VoteReadResult(f.ctx, v[i], id, r); err != nil { + t.Fatalf("vote %d: %v", i, err) + } + } + ur, found := f.k.GetUniversalRead(f.ctx, id) + require.True(t, found) + return ur.BallotKey +} + +func fireTerminal(f *testFixture, ballotKey string, status uvalidatortypes.BallotStatus) error { + return keeper.NewBallotHooks(f.k).AfterBallotTerminal( + f.ctx, ballotKey, + uvalidatortypes.BallotObservationType_BALLOT_OBSERVATION_TYPE_READ_RESULT, + status, + ) +} + +// The happy path: a passed ballot calls the contract and marks the read fulfilled. +func TestAfterBallotTerminal_FulfilsOnPassed(t *testing.T) { + f := SetupTest(t) + f.ctx = f.ctx.WithBlockHeight(10) + seedRead(t, f, "0xaa", 500) + + res := obs(0x42) + key := voteToQuorum(t, f, "0xaa", res) + + require.NoError(t, fireTerminal(f, key, uvalidatortypes.BallotStatus_BALLOT_STATUS_PASSED)) + + require.Equal(t, 1, f.evm.callsTo(types.MethodFulfillExternalCallback)) + require.Equal(t, 1, f.evm.callsTo(types.MethodReportCallbackGas), + "a successful fulfilment settles the gas in the same flow") + c, ok := f.evm.firstCallTo(types.MethodFulfillExternalCallback) + require.True(t, ok) + require.Equal(t, moduleEVMAddr(), c.from, "must be sent as the x/ucallback module account") + require.True(t, c.isModule) + require.Nil(t, c.gasLimit, "the contract enforces the callback budget, not us") + + // requestId reaches the contract as a uint256, not a string + require.Len(t, c.args, 2, + "fulfillExternalCallback takes only (requestId, resultData)") + require.Equal(t, big.NewInt(0xaa), c.args[0]) + require.Equal(t, []byte{0x42}, c.args[1]) + + ur, _ := f.k.GetUniversalRead(f.ctx, "0xaa") + require.Equal(t, types.UniversalReadStatus_UNIVERSAL_READ_STATUS_FULFILLED, ur.Status) + require.Len(t, ur.PcTx, 2, "the fulfil and the gas report are both recorded") + require.Equal(t, "SUCCESS", ur.PcTx[0].Status) + require.Equal(t, "0xEVMTX", ur.PcTx[0].TxHash) + require.Equal(t, moduleEVMAddr().Hex(), ur.PcTx[0].Sender) + require.Equal(t, "SUCCESS", ur.PcTx[1].Status) + + // settled, so it leaves the in-flight set + require.Empty(t, pendingIDs(t, f)) +} + +// The module account nonce lives in x/ucallback's own state, and every call must +// draw and advance it — a reused nonce is rejected by the EVM. +func TestFulfil_UsesAndAdvancesModuleNonce(t *testing.T) { + f := SetupTest(t) + f.ctx = f.ctx.WithBlockHeight(10) + require.NoError(t, f.k.ModuleAccountNonce.Set(f.ctx, 7)) + + seedRead(t, f, "0xaa", 500) + key := voteToQuorum(t, f, "0xaa", obs(0x01)) + require.NoError(t, fireTerminal(f, key, uvalidatortypes.BallotStatus_BALLOT_STATUS_PASSED)) + + fulfil, ok := f.evm.firstCallTo(types.MethodFulfillExternalCallback) + require.True(t, ok) + require.NotNil(t, fulfil.nonce) + require.Equal(t, uint64(7), *fulfil.nonce, "uses the stored value") + + report, ok := f.evm.firstCallTo(types.MethodReportCallbackGas) + require.True(t, ok) + require.Equal(t, uint64(8), *report.nonce, "the report takes the next one") + + got, err := f.k.GetModuleAccountNonce(f.ctx) + require.NoError(t, err) + require.Equal(t, uint64(9), got, "both calls advanced it") +} + +// Two calls in the same block must not reuse a nonce. +func TestModuleNonce_AdvancesPerCall(t *testing.T) { + f := SetupTest(t) + f.ctx = f.ctx.WithBlockHeight(10) + + for i, id := range []string{"0xaa", "0xbb", "0xcc"} { + seedRead(t, f, id, 500) + key := voteToQuorum(t, f, id, obs(byte(i+1))) + require.NoError(t, fireTerminal(f, key, uvalidatortypes.BallotStatus_BALLOT_STATUS_PASSED)) + } + + // every call, fulfil and report alike, draws the next nonce in sequence + for i, c := range f.evm.calls { + require.Equal(t, uint64(i), *c.nonce, "call %d", i) + } + + got, err := f.k.GetModuleAccountNonce(f.ctx) + require.NoError(t, err) + require.Equal(t, uint64(len(f.evm.calls)), got) +} + +// The address the contract admits is fixed by the module name. +func TestModuleAddress_IsStable(t *testing.T) { + f := SetupTest(t) + _, hex := f.k.GetModuleAddress(f.ctx) + require.Equal(t, "0x07a0258D367A4A4cd9d6E4b7eEE8E7eF491CC519", hex, + "UniversalCallback hardcodes this; changing the module name breaks every call") +} + +// selector returns a Solidity custom-error selector. +func selector(sig string) []byte { return crypto.Keccak256([]byte(sig))[:4] } + +// invalidStatus builds an InvalidRequestStatus revert reporting `actual`. +func invalidStatus(actual byte) []byte { + out := append([]byte{}, selector("InvalidRequestStatus(uint256,uint8,uint8)")...) + word := func(v byte) []byte { b := make([]byte, 32); b[31] = v; return b } + out = append(out, word(0xaa)...) + out = append(out, word(actual)...) + out = append(out, word(1)...) + return out +} + +// A revert means the whole transaction rolled back: fulfilledRequests stays false, +// _pending survives, _settle never ran, and the funder's deposit is still escrowed. +// Retiring the record would drop it from PendingByExpiry and leave nothing able to +// release those funds — only this module may call expireExternalRead. +func TestAfterBallotTerminal_UnsettledRevertLeavesInFlight(t *testing.T) { + f := SetupTest(t) + f.ctx = f.ctx.WithBlockHeight(10) + f.evm.vmErrors = []string{"execution reverted"} + f.evm.revertData = selector("CallerIsNotUCallbackModule()") + + seedRead(t, f, "0xaa", 500) + key := voteToQuorum(t, f, "0xaa", obs(0x01)) + require.NoError(t, fireTerminal(f, key, uvalidatortypes.BallotStatus_BALLOT_STATUS_PASSED)) + + ur, _ := f.k.GetUniversalRead(f.ctx, "0xaa") + require.Equal(t, types.UniversalReadStatus_UNIVERSAL_READ_STATUS_VOTING, ur.Status, + "nothing settled on the contract, so the read must stay in flight") + require.NotEmpty(t, ur.ErrorMsg, "but the reason is recorded") + require.Len(t, ur.PcTx, 1) + require.Equal(t, "FAILED", ur.PcTx[0].Status) + + // crucially, expiry can still reach it and refund the funder + require.Equal(t, []string{"0xaa"}, collectDueBy(t, f, 500)) +} + +// Out of gas is the same: real gas burned, but nothing persisted. +func TestAfterBallotTerminal_OutOfGasLeavesInFlight(t *testing.T) { + f := SetupTest(t) + f.ctx = f.ctx.WithBlockHeight(10) + f.evm.vmErrors = []string{"out of gas"} + + seedRead(t, f, "0xaa", 500) + key := voteToQuorum(t, f, "0xaa", obs(0x01)) + require.NoError(t, fireTerminal(f, key, uvalidatortypes.BallotStatus_BALLOT_STATUS_PASSED)) + + ur, _ := f.k.GetUniversalRead(f.ctx, "0xaa") + require.Equal(t, types.UniversalReadStatus_UNIVERSAL_READ_STATUS_VOTING, ur.Status) + require.Equal(t, []string{"0xaa"}, collectDueBy(t, f, 500)) +} + +// RequestAlreadyFulfilled is the one revert that IS terminal — the contract closed +// the request another way and the funder already has their refund. +func TestAfterBallotTerminal_AlreadySettledIsTerminal(t *testing.T) { + f := SetupTest(t) + f.ctx = f.ctx.WithBlockHeight(10) + f.evm.vmErrors = []string{"execution reverted"} + f.evm.revertData = invalidStatus(3) // SETTLED + + seedRead(t, f, "0xaa", 500) + key := voteToQuorum(t, f, "0xaa", obs(0x01)) + require.NoError(t, fireTerminal(f, key, uvalidatortypes.BallotStatus_BALLOT_STATUS_PASSED)) + + ur, _ := f.k.GetUniversalRead(f.ctx, "0xaa") + require.Equal(t, types.UniversalReadStatus_UNIVERSAL_READ_STATUS_FAILED, ur.Status) + require.Empty(t, collectDueBy(t, f, 500), "settled, so nothing left to expire") +} + +// A dispatch error produces no response at all — still unsettled. +func TestAfterBallotTerminal_CallErrorLeavesInFlight(t *testing.T) { + f := SetupTest(t) + f.ctx = f.ctx.WithBlockHeight(10) + + seedRead(t, f, "0xaa", 500) + key := voteToQuorum(t, f, "0xaa", obs(0x01)) + f.evm.callErr = errTest + + require.NoError(t, fireTerminal(f, key, uvalidatortypes.BallotStatus_BALLOT_STATUS_PASSED)) + + ur, _ := f.k.GetUniversalRead(f.ctx, "0xaa") + require.Equal(t, types.UniversalReadStatus_UNIVERSAL_READ_STATUS_VOTING, ur.Status) + require.Contains(t, ur.ErrorMsg, "injected") + require.Equal(t, []string{"0xaa"}, collectDueBy(t, f, 500)) +} + +// Re-firing the hook must not call the contract twice. This is what makes the +// "settled reads are not findable by ballot" semantic from C3 load-bearing. +func TestAfterBallotTerminal_IsIdempotent(t *testing.T) { + f := SetupTest(t) + f.ctx = f.ctx.WithBlockHeight(10) + + seedRead(t, f, "0xaa", 500) + key := voteToQuorum(t, f, "0xaa", obs(0x01)) + + require.NoError(t, fireTerminal(f, key, uvalidatortypes.BallotStatus_BALLOT_STATUS_PASSED)) + require.NoError(t, fireTerminal(f, key, uvalidatortypes.BallotStatus_BALLOT_STATUS_PASSED)) + require.NoError(t, fireTerminal(f, key, uvalidatortypes.BallotStatus_BALLOT_STATUS_PASSED)) + + require.Equal(t, 1, f.evm.callsTo(types.MethodFulfillExternalCallback), + "the contract must be fulfilled exactly once") + require.Equal(t, 1, f.evm.callsTo(types.MethodReportCallbackGas), + "and settled exactly once") +} + +// Neither EXPIRED nor REJECTED retires a request here — expiry belongs to the +// sweeper, which sees every overdue request rather than only those with a ballot. +func TestAfterBallotTerminal_NonPassedLeavesToSweeper(t *testing.T) { + for _, status := range []uvalidatortypes.BallotStatus{ + uvalidatortypes.BallotStatus_BALLOT_STATUS_EXPIRED, + uvalidatortypes.BallotStatus_BALLOT_STATUS_REJECTED, + } { + t.Run(status.String(), func(t *testing.T) { + f := SetupTest(t) + f.ctx = f.ctx.WithBlockHeight(10) + + seedRead(t, f, "0xaa", 500) + key := voteToQuorum(t, f, "0xaa", obs(0x01)) + + require.NoError(t, fireTerminal(f, key, status)) + + require.Empty(t, f.evm.calls, "the hook must not call the contract") + ur, _ := f.k.GetUniversalRead(f.ctx, "0xaa") + require.Equal(t, types.UniversalReadStatus_UNIVERSAL_READ_STATUS_VOTING, ur.Status) + require.Equal(t, []string{"0xaa"}, pendingIDs(t, f), + "still in flight, so the sweeper can find it") + }) + } +} + +func TestAfterBallotTerminal_RejectedLeavesInFlight(t *testing.T) { + f := SetupTest(t) + f.ctx = f.ctx.WithBlockHeight(10) + + seedRead(t, f, "0xaa", 500) + key := voteToQuorum(t, f, "0xaa", obs(0x01)) + + require.NoError(t, fireTerminal(f, key, uvalidatortypes.BallotStatus_BALLOT_STATUS_REJECTED)) + + require.Empty(t, f.evm.calls, "no contract call for a rejected ballot") + ur, _ := f.k.GetUniversalRead(f.ctx, "0xaa") + require.Equal(t, types.UniversalReadStatus_UNIVERSAL_READ_STATUS_VOTING, ur.Status) + require.Equal(t, []string{"0xaa"}, pendingIDs(t, f), + "still offered — validators may yet agree") +} + +// Ballots belonging to other modules must be ignored outright. +func TestAfterBallotTerminal_IgnoresOtherBallotTypes(t *testing.T) { + f := SetupTest(t) + f.ctx = f.ctx.WithBlockHeight(10) + + seedRead(t, f, "0xaa", 500) + key := voteToQuorum(t, f, "0xaa", obs(0x01)) + + for _, bt := range []uvalidatortypes.BallotObservationType{ + uvalidatortypes.BallotObservationType_BALLOT_OBSERVATION_TYPE_INBOUND_TX, + uvalidatortypes.BallotObservationType_BALLOT_OBSERVATION_TYPE_OUTBOUND_TX, + uvalidatortypes.BallotObservationType_BALLOT_OBSERVATION_TYPE_TSS_KEY, + } { + require.NoError(t, keeper.NewBallotHooks(f.k).AfterBallotTerminal( + f.ctx, key, bt, uvalidatortypes.BallotStatus_BALLOT_STATUS_PASSED)) + } + + require.Empty(t, f.evm.calls, "only READ_RESULT ballots may drive fulfilment") +} + +// An unknown ballot is not an error — the hook fires for every module's ballots. +func TestAfterBallotTerminal_UnknownBallotIsNoop(t *testing.T) { + f := SetupTest(t) + require.NoError(t, fireTerminal(f, "not-a-ballot-of-ours", + uvalidatortypes.BallotStatus_BALLOT_STATUS_PASSED)) + require.Empty(t, f.evm.calls) +} + +// Batched siblings settle independently: fulfilling one must not touch the other. +func TestAfterBallotTerminal_BatchSiblingsIndependent(t *testing.T) { + f := SetupTest(t) + f.ctx = f.ctx.WithBlockHeight(10) + + require.NoError(t, f.k.SetUniversalRead(f.ctx, + newRead("0xaa", "0xBATCH", 500, types.UniversalReadStatus_UNIVERSAL_READ_STATUS_PENDING))) + require.NoError(t, f.k.SetUniversalRead(f.ctx, + newRead("0xbb", "0xBATCH", 500, types.UniversalReadStatus_UNIVERSAL_READ_STATUS_PENDING))) + + key := voteToQuorum(t, f, "0xaa", obs(0x01)) + require.NoError(t, fireTerminal(f, key, uvalidatortypes.BallotStatus_BALLOT_STATUS_PASSED)) + + a, _ := f.k.GetUniversalRead(f.ctx, "0xaa") + b, _ := f.k.GetUniversalRead(f.ctx, "0xbb") + require.Equal(t, types.UniversalReadStatus_UNIVERSAL_READ_STATUS_FULFILLED, a.Status) + require.Equal(t, types.UniversalReadStatus_UNIVERSAL_READ_STATUS_PENDING, b.Status) + require.Equal(t, []string{"0xbb"}, pendingIDs(t, f)) +} diff --git a/x/ucallback/keeper/evm.go b/x/ucallback/keeper/evm.go new file mode 100644 index 00000000..2bb68fb1 --- /dev/null +++ b/x/ucallback/keeper/evm.go @@ -0,0 +1,258 @@ +package keeper + +import ( + "fmt" + "math/big" + + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + evmtypes "github.com/cosmos/evm/x/vm/types" + "github.com/ethereum/go-ethereum/common" + + pchaintypes "github.com/pushchain/push-chain-node/types" + "github.com/pushchain/push-chain-node/x/ucallback/types" + uexecutortypes "github.com/pushchain/push-chain-node/x/uexecutor/types" + uregistrytypes "github.com/pushchain/push-chain-node/x/uregistry/types" +) + +// universalCallbackAddress is the system contract x/ucallback drives. +func universalCallbackAddress() common.Address { + return common.HexToAddress(uregistrytypes.SYSTEM_CONTRACTS["UNIVERSAL_CALLBACK"].Address) +} + +// requestIDToUint256 converts a stored request id back to the uint256 the contract +// expects. Ingest keeps the raw 32-byte topic hex precisely so this is a parse and +// not a base conversion. +func requestIDToUint256(requestID string) (*big.Int, error) { + v, ok := new(big.Int).SetString(trim0x(requestID), 16) + if !ok { + return nil, fmt.Errorf("request id %q is not hex", requestID) + } + return v, nil +} + +func trim0x(s string) string { + if len(s) >= 2 && (s[:2] == "0x" || s[:2] == "0X") { + return s[2:] + } + return s +} + +// callAsModule issues a DerivedEVMCall to UniversalCallback from the x/ucallback +// module account. +// +// That account is the only sender UniversalCallback's access control admits, and +// this module is its only user — so the nonce counter lives here, alongside the +// account it belongs to. Every call must draw and advance it, or the second call in +// a block reuses a consumed nonce and is rejected. +func (k Keeper) callAsModule( + ctx sdk.Context, + method string, + args ...interface{}, +) (*evmtypes.MsgEthereumTxResponse, error) { + callbackABI, err := types.ParseUniversalCallbackABI() + if err != nil { + return nil, err + } + + from, _ := k.GetModuleAddress(ctx) + + nonce, err := k.GetModuleAccountNonce(ctx) + if err != nil { + return nil, fmt.Errorf("failed to read module account nonce: %w", err) + } + if _, err := k.IncrementModuleAccountNonce(ctx); err != nil { + return nil, fmt.Errorf("failed to advance module account nonce: %w", err) + } + + data, err := callbackABI.Pack(method, args...) + if err != nil { + return nil, fmt.Errorf("failed to pack %s: %w", method, err) + } + + // DerivedEVMCallWithData, not the ABI-typed DerivedEVMCall wrapper: on a revert + // the wrapper returns (nil, err), throwing away the response — and with it + // res.Ret, the revert data. ClassifyCall reads that data to tell "already + // settled" from "try again", so routing through the wrapper would collapse every + // revert into CallUnsettled and make the distinction unreachable. This layer + // returns (res, err) together, which is what its own doc comment describes. + contract := universalCallbackAddress() + return k.evmKeeper.DerivedEVMCallWithData( + ctx, + from, + &contract, + data, + true, // commit + false, // not gasless — we want gas accounted in the receipt + true, // isModuleSender + big.NewInt(0), + // nil gas limit — the callback's own budget is enforced by the contract + // (callbackGasLimit, capped at MAX_CALLBACK_GAS_LIMIT), so a limit here + // would only add a second ceiling that could cut the callback short. + nil, + &nonce, + ) +} + +// CallFulfillExternalCallback delivers a finalized observation to the contract, +// which forwards it to the requesting app's callback. +func (k Keeper) CallFulfillExternalCallback( + ctx sdk.Context, + requestID string, + result *types.ReadResult, +) (*evmtypes.MsgEthereumTxResponse, error) { + if result == nil { + return nil, fmt.Errorf("cannot fulfil %s: nil result", requestID) + } + + id, err := requestIDToUint256(requestID) + if err != nil { + return nil, err + } + + k.Logger().Debug("EVM call: fulfillExternalCallback", + "request_id", requestID, + "result_len", len(result.ResultData), + ) + + return k.callAsModule(ctx, + types.MethodFulfillExternalCallback, + id, + result.ResultData, + ) +} + +// CallExpireExternalRead retires a request the contract will no longer accept. +func (k Keeper) CallExpireExternalRead( + ctx sdk.Context, + requestID string, +) (*evmtypes.MsgEthereumTxResponse, error) { + id, err := requestIDToUint256(requestID) + if err != nil { + return nil, err + } + + k.Logger().Debug("EVM call: expireExternalRead", "request_id", requestID) + + return k.callAsModule(ctx, types.MethodExpireExternalRead, id) +} + +// pcTxFrom renders an EVM call attempt as a PCTx audit entry. Both the success and +// failure paths produce one, so a request's history shows every attempt made on it +// rather than only the one that stuck. +func pcTxFrom(ctx sdk.Context, sender string, res *evmtypes.MsgEthereumTxResponse, callErr error) *uexecutortypes.PCTx { + pcTx := &uexecutortypes.PCTx{ + Sender: sender, + BlockHeight: uint64(ctx.BlockHeight()), + Status: "SUCCESS", + } + if res != nil { + pcTx.TxHash = res.Hash + pcTx.GasUsed = res.GasUsed + if res.VmError != "" { + pcTx.Status = "FAILED" + pcTx.ErrorMsg = res.VmError + } + } + if callErr != nil { + pcTx.Status = "FAILED" + pcTx.ErrorMsg = callErr.Error() + } + return pcTx +} + +// ErrBudgetTooSmall is recorded on a read whose callback budget cannot cover the +// gas its app declared it needs. Fixed text, set by us from a deterministic +// comparison — it never comes from a validator and never touches a ballot. +const ErrBudgetTooSmall = "callback budget does not cover the declared callback gas limit" + +// CallbackCost prices a gas figure at the current base fee. +// +// Same valuation x/uexecutor applies to UEA execution, so a read and a payload +// execution are charged alike. +func (k Keeper) CallbackCost(ctx sdk.Context, gas uint64) (*big.Int, error) { + baseFee := k.feemarketKeeper.GetBaseFee(ctx) + if baseFee.IsNil() { + return nil, fmt.Errorf("base fee unavailable") + } + return new(big.Int).Mul( + new(big.Int).SetUint64(gas), + baseFee.TruncateInt().BigInt(), + ), nil +} + +// CanAffordCallback reports whether the request funded the gas it declared. +// +// All-or-nothing on purpose. Executing a partially funded callback would hand the +// app less gas than it asked for, which almost certainly runs out anyway — the user +// then pays for a doomed attempt instead of getting a full refund. +func (k Keeper) CanAffordCallback(ctx sdk.Context, req *types.ReadRequest) (bool, error) { + if req == nil { + return false, fmt.Errorf("nil read request") + } + cost, err := k.CallbackCost(ctx, req.CallbackGasLimit) + if err != nil { + return false, err + } + budget, err := parseBudget(req.CallbackBudget) + if err != nil { + return false, err + } + return budget.Cmp(cost) >= 0, nil +} + +// parseBudget reads a uint256 decimal string, treating empty as zero. Records +// ingested before the fee split existed carry no budget, and an unfunded read is +// the honest reading of that — not a malformed one. +func parseBudget(s string) (*big.Int, error) { + if s == "" { + return big.NewInt(0), nil + } + v, ok := new(big.Int).SetString(s, 10) + if !ok { + return nil, fmt.Errorf("callback budget %q is not a decimal integer", s) + } + return v, nil +} + +// CallReportCallbackGas settles an executed request, returning the amount the +// contract clamped the report to. +func (k Keeper) CallReportCallbackGas( + ctx sdk.Context, requestID string, cost *big.Int, +) (*evmtypes.MsgEthereumTxResponse, error) { + id, err := requestIDToUint256(requestID) + if err != nil { + return nil, err + } + k.Logger().Debug("EVM call: reportCallbackGas", "request_id", requestID, "cost", cost.String()) + return k.callAsModule(ctx, types.MethodReportCallbackGas, id, cost) +} + +// TakeAndBurn moves the consumed callback budget out of UniversalCallback and +// destroys it. +// +// No contract API is involved: a contract's balance is an ordinary bank balance, so +// the module debits it directly — the same shape as x/uexecutor's DeductAndBurnFees. +// reportCallbackGas has already released the refund and decremented totalEscrowed, +// so `amount` is exactly the unattributed slack the contract left behind for us. +func (k Keeper) TakeAndBurn(ctx sdk.Context, amount *big.Int) error { + if amount == nil || amount.Sign() <= 0 { + return nil + } + coins := sdk.NewCoins(sdk.NewCoin( + pchaintypes.BaseDenom, sdkmath.NewIntFromBigInt(amount), + )) + + contractAcc := sdk.AccAddress(universalCallbackAddress().Bytes()) + if err := k.bankKeeper.SendCoinsFromAccountToModule( + ctx, contractAcc, types.ModuleName, coins, + ); err != nil { + return fmt.Errorf("failed to take burned callback gas from the contract: %w", err) + } + if err := k.bankKeeper.BurnCoins(ctx, types.ModuleName, coins); err != nil { + return fmt.Errorf("failed to burn callback gas: %w", err) + } + + k.Logger().Info("callback gas burned", "amount", amount.String()) + return nil +} diff --git a/x/ucallback/keeper/evm_fake_test.go b/x/ucallback/keeper/evm_fake_test.go new file mode 100644 index 00000000..30dab0e3 --- /dev/null +++ b/x/ucallback/keeper/evm_fake_test.go @@ -0,0 +1,229 @@ +package keeper_test + +import ( + "context" + "fmt" + "math/big" + + sdkmath "cosmossdk.io/math" + + ethcommon "github.com/ethereum/go-ethereum/common" + + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + evmtypes "github.com/cosmos/evm/x/vm/types" + + pchaintypes "github.com/pushchain/push-chain-node/types" + "github.com/pushchain/push-chain-node/x/ucallback/types" + uregistrytypes "github.com/pushchain/push-chain-node/x/uregistry/types" +) + +// recordedCall captures one DerivedEVMCall so tests can assert on what was sent to +// the contract, not merely that something was. +type recordedCall struct { + from ethcommon.Address + contract ethcommon.Address + method string + args []interface{} + nonce *uint64 + gasLimit *big.Int + isModule bool +} + +type fakeEVM struct { + calls []recordedCall + + // per-call outcomes, consumed in order; the zero value means success + vmErrors []string + // revertData is returned alongside every vmError — set it to a custom-error + // selector to exercise the classification path. + revertData []byte + callErr error + // gasUsed overrides the receipt's reported gas; zero means the default. + gasUsed uint64 +} + +var _ types.EVMKeeper = (*fakeEVM)(nil) + +// DerivedEVMCallWithData is the entry point production uses. It unpacks the call +// data back into method + args, so these tests also prove our ABI packing +// round-trips through the real UniversalCallback ABI rather than just recording +// whatever the keeper claims it sent. +func (f *fakeEVM) DerivedEVMCallWithData( + _ sdk.Context, + from ethcommon.Address, + contract *ethcommon.Address, + data []byte, + _, _, isModuleSender bool, + _, gasLimit *big.Int, + manualNonce *uint64, +) (*evmtypes.MsgEthereumTxResponse, error) { + method, args, err := unpackCallbackCall(data) + if err != nil { + return nil, err + } + + var n *uint64 + if manualNonce != nil { + v := *manualNonce + n = &v + } + var to ethcommon.Address + if contract != nil { + to = *contract + } + f.calls = append(f.calls, recordedCall{ + from: from, contract: to, method: method, args: args, + nonce: n, gasLimit: gasLimit, isModule: isModuleSender, + }) + + if f.callErr != nil { + return nil, f.callErr + } + + gas := uint64(21_000) + if f.gasUsed != 0 { + gas = f.gasUsed + } + res := &evmtypes.MsgEthereumTxResponse{ + Hash: "0xEVMTX", + GasUsed: gas, + } + if len(f.vmErrors) > 0 { + vmErr := f.vmErrors[0] + f.vmErrors = f.vmErrors[1:] + // An empty entry means "this call succeeds" — queues use it to let an + // earlier call through and fail a later one. + if vmErr != "" { + res.VmError = vmErr + res.Ret = f.revertData + + // The real layer returns the response AND an error on a revert + // (call_evm.go:323). Returning only the response here would let a + // classification bug that trips on callErr pass unnoticed. + return res, fmt.Errorf("%s: ret 0x%x", res.VmError, res.Ret) + } + } + return res, nil +} + +// unpackCallbackCall turns raw call data back into a method name and its arguments +// using the real ABI. +func unpackCallbackCall(data []byte) (string, []interface{}, error) { + if len(data) < 4 { + return "", nil, fmt.Errorf("call data too short: %d bytes", len(data)) + } + parsed, err := types.ParseUniversalCallbackABI() + if err != nil { + return "", nil, err + } + m, err := parsed.MethodById(data[:4]) + if err != nil { + return "", nil, err + } + args, err := m.Inputs.Unpack(data[4:]) + if err != nil { + return "", nil, fmt.Errorf("unpack %s: %w", m.Name, err) + } + return m.Name, args, nil +} + +func (f *fakeEVM) lastCall() recordedCall { return f.calls[len(f.calls)-1] } + +// callsTo counts contract calls by method. Fulfilment now issues two — the +// callback and the gas report — so assertions name the method rather than a total. +func (f *fakeEVM) callsTo(method string) int { + n := 0 + for _, c := range f.calls { + if c.method == method { + n++ + } + } + return n +} + +// firstCallTo returns the first call to a method, for asserting its arguments. +func (f *fakeEVM) firstCallTo(method string) (recordedCall, bool) { + for _, c := range f.calls { + if c.method == method { + return c, true + } + } + return recordedCall{}, false +} + +// fakeAccount resolves the module account. The nonce is no longer faked — it lives +// in x/ucallback's own state now, so the tests exercise the real counter. +type fakeAccount struct { + addr sdk.AccAddress +} + +var _ types.AccountKeeper = (*fakeAccount)(nil) + +func (f *fakeAccount) GetModuleAccount(context.Context, string) sdk.ModuleAccountI { + return authtypes.NewEmptyModuleAccount(types.ModuleName) +} + +// fakeBank records what the module moved and destroyed. Tracks a notional contract +// balance so a take-out larger than the contract holds fails the way bank would. +type fakeBank struct { + contractBalance sdkmath.Int + sentFrom sdk.AccAddress + sentTo string + sentAmount sdkmath.Int + burnedFrom string + burned sdkmath.Int + + sendErr error + burnErr error +} + +var _ types.BankKeeper = (*fakeBank)(nil) + +func newFakeBank() *fakeBank { + return &fakeBank{ + contractBalance: sdkmath.NewInt(0), + sentAmount: sdkmath.NewInt(0), + burned: sdkmath.NewInt(0), + } +} + +func (b *fakeBank) SendCoinsFromAccountToModule(_ context.Context, from sdk.AccAddress, module string, amt sdk.Coins) error { + if b.sendErr != nil { + return b.sendErr + } + a := amt.AmountOf(pchaintypes.BaseDenom) + if a.GT(b.contractBalance) { + return fmt.Errorf("insufficient funds: %s < %s", b.contractBalance, a) + } + b.contractBalance = b.contractBalance.Sub(a) + b.sentFrom, b.sentTo = from, module + b.sentAmount = b.sentAmount.Add(a) + return nil +} + +func (b *fakeBank) BurnCoins(_ context.Context, module string, amt sdk.Coins) error { + if b.burnErr != nil { + return b.burnErr + } + b.burnedFrom = module + b.burned = b.burned.Add(amt.AmountOf(pchaintypes.BaseDenom)) + return nil +} + +func (b *fakeBank) GetBalance(_ context.Context, _ sdk.AccAddress, denom string) sdk.Coin { + return sdk.NewCoin(denom, b.contractBalance) +} + +// fakeFeeMarket serves a fixed base fee so gas pricing in tests is exact. +type fakeFeeMarket struct{ baseFee sdkmath.LegacyDec } + +var _ types.FeeMarketKeeper = (*fakeFeeMarket)(nil) + +func (f *fakeFeeMarket) GetBaseFee(sdk.Context) sdkmath.LegacyDec { return f.baseFee } + +// contractAccAddr is UniversalCallback's account, the source of the escrow. +func contractAccAddr() sdk.AccAddress { + return sdk.AccAddress(ethcommon.HexToAddress( + uregistrytypes.SYSTEM_CONTRACTS["UNIVERSAL_CALLBACK"].Address).Bytes()) +} diff --git a/x/ucallback/keeper/evm_hooks.go b/x/ucallback/keeper/evm_hooks.go new file mode 100644 index 00000000..d539556a --- /dev/null +++ b/x/ucallback/keeper/evm_hooks.go @@ -0,0 +1,77 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + evmtypes "github.com/cosmos/evm/x/vm/types" + "github.com/ethereum/go-ethereum/common" + core "github.com/ethereum/go-ethereum/core" + ethtypes "github.com/ethereum/go-ethereum/core/types" +) + +// EVMHooks implements the EVM post-processing hooks for x/ucallback. +// +// Runs after every EVM transaction, so the log filter in IngestReadRequests must +// stay tight: this hook sees traffic for the whole chain and must be a no-op for +// all of it except UniversalCallback's ReadRequested events. +type EVMHooks struct { + k Keeper +} + +// NewEVMHooks creates a new instance of EVMHooks. +func NewEVMHooks(k Keeper) evmtypes.EvmHooks { + return EVMHooks{k: k} +} + +// PostTxProcessing inspects the receipt and records a UniversalRead for every +// ReadRequested event the transaction emitted. +// +// Returning an error reverts the whole EVM transaction. That is the behaviour we +// want here: a ReadRequested log we cannot record is a request the user paid for +// that no validator would ever serve. Reverting returns their fee instead of +// stranding it. +func (h EVMHooks) PostTxProcessing( + ctx sdk.Context, + sender common.Address, + msg core.Message, + receipt *ethtypes.Receipt, +) error { + if receipt == nil || len(receipt.Logs) == 0 { + return nil + } + + protoReceipt := &evmtypes.MsgEthereumTxResponse{ + Hash: receipt.TxHash.Hex(), + GasUsed: receipt.GasUsed, + Logs: convertReceiptLogs(receipt.Logs), + } + + return h.k.IngestReadRequests(ctx, protoReceipt) +} + +func convertReceiptLogs(logs []*ethtypes.Log) []*evmtypes.Log { + out := make([]*evmtypes.Log, 0, len(logs)) + + for _, l := range logs { + out = append(out, &evmtypes.Log{ + Address: l.Address.Hex(), + Topics: convertTopics(l.Topics), + Data: l.Data, + BlockNumber: l.BlockNumber, + TxHash: l.TxHash.Hex(), + TxIndex: uint64(l.TxIndex), + BlockHash: l.BlockHash.Hex(), + Index: uint64(l.Index), + Removed: l.Removed, + }) + } + + return out +} + +func convertTopics(topics []common.Hash) []string { + out := make([]string, len(topics)) + for i, t := range topics { + out[i] = t.Hex() + } + return out +} diff --git a/x/ucallback/keeper/expire.go b/x/ucallback/keeper/expire.go new file mode 100644 index 00000000..ad1c96b3 --- /dev/null +++ b/x/ucallback/keeper/expire.go @@ -0,0 +1,145 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/pushchain/push-chain-node/x/ucallback/types" +) + +// MaxExpiriesPerBlock bounds how many requests one EndBlocker may retire. +// +// Each expiry is a real EVM call, so an unbounded sweep would let a backlog turn a +// single block into an arbitrarily expensive one. The bound is a rate limit, not a +// cap: whatever is left over is picked up next block, and the set is ordered by +// deadline so the longest-overdue always go first. +const MaxExpiriesPerBlock = 50 + +// MaxExpiryAttempts bounds how many times one request's expiry call may fail +// before the chain stops trying. +// +// Retrying matters because expiry now moves money: UniversalCallback._settle +// credits the funder's refund, and expireExternalRead is module-gated, so if we +// stop calling nobody else can. A transient failure that we treated as final would +// strand the refund permanently. +// +// Bounded because two of the contract's three reverts are permanent — +// RequestAlreadyFulfilled and InvalidCallbackTarget both mean the request was +// already settled by the fulfil path, so the money is safe and retrying is pure +// waste. Three attempts distinguishes the transient case without looping forever. +const MaxExpiryAttempts = 3 + +// SweepExpired retires every read whose deadline has passed. +// +// This is the only path by which a request expires. Nothing else can trigger it, +// because a deadline passing is not an event — it is just time going by, so +// somebody has to look. Fulfilment has an event to hang off (a ballot reaching +// quorum); expiry does not. +func (k Keeper) SweepExpired(ctx sdk.Context) error { + height := uint64(ctx.BlockHeight()) + + // Phase 1 — collect. IterateExpiredBy walks PendingByExpiry, and ExpireRead + // removes from it. Mutating a collection while iterating it skips entries at + // best and panics at worst, so the walk finishes before anything is written. + // Same two-phase shape as x/uvalidator's ExpireBallotsBeforeHeight. + due := make([]types.UniversalRead, 0, MaxExpiriesPerBlock) + if err := k.IterateExpiredBy(ctx, height, func(ur types.UniversalRead) bool { + // No status filter is needed here, though expireExternalRead requires the + // contract to be PENDING. A read only reaches EXECUTED there if fulfilment + // succeeded, and that sets a terminal status which drops it out of this very + // set — so anything still in flight is still PENDING on the contract. + due = append(due, ur) + return len(due) < MaxExpiriesPerBlock + }); err != nil { + return err + } + if len(due) == 0 { + return nil + } + + k.Logger().Debug("sweeping expired read requests", "count", len(due), "height", height) + + // Phase 2 — act. + for _, ur := range due { + if err := k.ExpireRead(ctx, ur); err != nil { + // One unwritable record must not abort the block or stop the rest of + // the sweep. ExpireRead already absorbs contract-level failures; an + // error here means the state write itself failed. + k.Logger().Error("failed to expire read request", + "request_id", ur.Id, "err", err.Error()) + } + } + + return nil +} + +// ExpireRead retires one request: tell the contract, record the attempt, and mark +// the record terminal once the contract has acknowledged it. +// +// A failed call leaves the request in flight so the next block retries it, up to +// MaxExpiryAttempts, tracked by ExpiryAttempts. +// +// Deliberately not len(PcTx): that slice holds every EVM attempt on the request, +// and a fulfilment that failed without settling leaves its entry behind while the +// read stays in flight. Counting entries would hand exactly those reads a shorter +// retry budget than a read that reached the sweeper cleanly. +func (k Keeper) ExpireRead(ctx sdk.Context, ur types.UniversalRead) error { + _, moduleHex := k.GetModuleAddress(ctx) + + // The EVM call runs against a scratch state so a revert leaves nothing behind — + // in particular the module nonce increment inside callAsModule must not land + // when no transaction actually happened. + tmpCtx, commit := ctx.CacheContext() + res, callErr := k.CallExpireExternalRead(tmpCtx, ur.Id) + + var vmErr string + var revertData []byte + if res != nil { + vmErr, revertData = res.VmError, res.Ret + } + outcome := types.ClassifyCall(vmErr, revertData, callErr) + + if outcome == types.CallOK { + commit() + } + + ur.PcTx = append(ur.PcTx, pcTxFrom(ctx, moduleHex, res, callErr)) + ur.ExpiryAttempts++ + + switch { + case outcome == types.CallOK: + // Terminal status removes it from PendingByExpiry, so it is never swept twice. + ur.Status = types.UniversalReadStatus_UNIVERSAL_READ_STATUS_EXPIRED + k.Logger().Info("read request expired", + "request_id", ur.Id, "tx_hash", pcTxHash(res), "attempts", ur.ExpiryAttempts) + + case outcome == types.CallAlreadySettled: + // The contract already closed this request, so there is nothing to expire. + // Terminal immediately rather than burning the remaining attempts on a + // revert that will repeat identically. + ur.Status = types.UniversalReadStatus_UNIVERSAL_READ_STATUS_EXPIRED + k.Logger().Info("read already settled on the contract, retiring", + "request_id", ur.Id, "error", pcTxError(res, callErr)) + + case ur.ExpiryAttempts < MaxExpiryAttempts: + // Status untouched, so the request stays in PendingByExpiry and the next + // block tries again. + k.Logger().Warn("read expiry call failed, will retry", + "request_id", ur.Id, "attempt", ur.ExpiryAttempts, + "of", MaxExpiryAttempts, "error", pcTxError(res, callErr)) + + default: + // Out of attempts. ABORTED, not EXPIRED: EXPIRED asserts the contract + // accepted the expiry and credited the refund, and here it never did. The + // contract may still hold the request as pending, and since + // expireExternalRead is module-gated nobody else can settle it — so this + // state means "needs manual intervention", not "finished". + // + // Still terminal, so the sweeper stops spending a slot on it every block. + ur.Status = types.UniversalReadStatus_UNIVERSAL_READ_STATUS_ABORTED + ur.ErrorMsg = pcTxError(res, callErr) + k.Logger().Error("read expiry abandoned; contract may still hold the request and the refund is unsettled", + "request_id", ur.Id, "attempts", ur.ExpiryAttempts, "error", ur.ErrorMsg) + } + + return k.SetUniversalRead(ctx, ur) +} diff --git a/x/ucallback/keeper/expire_test.go b/x/ucallback/keeper/expire_test.go new file mode 100644 index 00000000..0bd3fb95 --- /dev/null +++ b/x/ucallback/keeper/expire_test.go @@ -0,0 +1,420 @@ +package keeper_test + +import ( + "fmt" + "math/big" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/pushchain/push-chain-node/x/ucallback/keeper" + "github.com/pushchain/push-chain-node/x/ucallback/types" + uvalidatortypes "github.com/pushchain/push-chain-node/x/uvalidator/types" +) + +// expiredIDs returns the request ids the sweeper called the contract for. +func expiredIDs(f *testFixture) []string { + var got []string + for _, c := range f.evm.calls { + if c.method == types.MethodExpireExternalRead { + got = append(got, fmt.Sprintf("0x%x", c.args[0].(*big.Int))) + } + } + return got +} + +// Only requests past their deadline are retired, and the boundary is exclusive — +// matching the query filter and the vote guard. +func TestSweepExpired_RetiresOnlyOverdue(t *testing.T) { + f := SetupTest(t) + f.ctx = f.ctx.WithBlockHeight(100) + + seedRead(t, f, "0x50", 50) // overdue + seedRead(t, f, "0x64", 100) // exactly at the deadline — already too late + seedRead(t, f, "0xc8", 200) // still live + + require.NoError(t, f.k.SweepExpired(f.ctx)) + + require.ElementsMatch(t, []string{"0x50", "0x64"}, expiredIDs(f)) + + for _, id := range []string{"0x50", "0x64"} { + ur, _ := f.k.GetUniversalRead(f.ctx, id) + require.Equal(t, types.UniversalReadStatus_UNIVERSAL_READ_STATUS_EXPIRED, ur.Status, id) + require.Len(t, ur.PcTx, 1, id) + } + live, _ := f.k.GetUniversalRead(f.ctx, "0xc8") + require.Equal(t, types.UniversalReadStatus_UNIVERSAL_READ_STATUS_PENDING, live.Status) + require.Equal(t, []string{"0xc8"}, pendingIDs(t, f)) +} + +// A second sweep must not touch what the first already retired. +func TestSweepExpired_IsIdempotent(t *testing.T) { + f := SetupTest(t) + f.ctx = f.ctx.WithBlockHeight(100) + seedRead(t, f, "0xaa", 50) + + require.NoError(t, f.k.SweepExpired(f.ctx)) + require.Len(t, f.evm.calls, 1) + + require.NoError(t, f.k.SweepExpired(f.ctx)) + require.NoError(t, f.k.SweepExpired(f.ctx)) + require.Len(t, f.evm.calls, 1, "a retired request must never be swept again") + + ur, _ := f.k.GetUniversalRead(f.ctx, "0xaa") + require.Len(t, ur.PcTx, 1) +} + +// A request that reached quorum is gone from the in-flight set, so the sweeper can +// never expire something already fulfilled — even past its deadline. +func TestSweepExpired_SkipsFulfilled(t *testing.T) { + f := SetupTest(t) + f.ctx = f.ctx.WithBlockHeight(10) + + seedRead(t, f, "0xaa", 50) + key := voteToQuorum(t, f, "0xaa", obs(0x01)) + require.NoError(t, fireTerminal(f, key, uvalidatortypes.BallotStatus_BALLOT_STATUS_PASSED)) + require.Equal(t, 1, f.evm.callsTo(types.MethodFulfillExternalCallback), "fulfilled") + + // now well past the deadline + f.ctx = f.ctx.WithBlockHeight(999) + require.NoError(t, f.k.SweepExpired(f.ctx)) + + require.Empty(t, expiredIDs(f), "must not expire a fulfilled request") + ur, _ := f.k.GetUniversalRead(f.ctx, "0xaa") + require.Equal(t, types.UniversalReadStatus_UNIVERSAL_READ_STATUS_FULFILLED, ur.Status) +} + +// A request validators diverged on has several ballots but is one entry in the +// in-flight set, so it is retired once — expiry credits the funder a refund +// (UniversalCallback._settle), so a second call would not be merely redundant. +func TestSweepExpired_DivergedRequestRetiredOnce(t *testing.T) { + f := SetupTest(t) + f.ctx = f.ctx.WithBlockHeight(10) + v := seedVoters(t, f, 4) + seedRead(t, f, "0xaa", 50) + + _, err := f.k.VoteReadResult(f.ctx, v[0], "0xaa", obs(0x01)) + require.NoError(t, err) + _, err = f.k.VoteReadResult(f.ctx, v[1], "0xaa", obs(0x02)) + require.NoError(t, err) + require.Equal(t, 2, f.uvalidator.ballotCount(), "validators diverged") + + f.ctx = f.ctx.WithBlockHeight(100) + require.NoError(t, f.k.SweepExpired(f.ctx)) + + require.Equal(t, []string{"0xaa"}, expiredIDs(f), "one request, one expiry") + ur, _ := f.k.GetUniversalRead(f.ctx, "0xaa") + require.Len(t, ur.PcTx, 1) +} + +// A failed call leaves the request in flight so the next block retries it. +// Expiry credits the funder a refund and only this module may call it, so treating +// a transient failure as final would strand that money for good. +func TestSweepExpired_RetriesTransientFailure(t *testing.T) { + f := SetupTest(t) + f.ctx = f.ctx.WithBlockHeight(100) + f.evm.vmErrors = []string{"execution reverted"} // first attempt only + seedRead(t, f, "0xaa", 50) + + require.NoError(t, f.k.SweepExpired(f.ctx)) + + ur, _ := f.k.GetUniversalRead(f.ctx, "0xaa") + require.Equal(t, types.UniversalReadStatus_UNIVERSAL_READ_STATUS_PENDING, ur.Status, + "not retired — the contract never acknowledged it") + require.Len(t, ur.PcTx, 1) + require.Equal(t, "FAILED", ur.PcTx[0].Status) + // NB: not pendingIDs — that query withholds anything past its deadline, so it + // is empty either way. The sweeper's own view is what matters here. + require.Equal(t, []string{"0xaa"}, collectDueBy(t, f, 100), + "still in the in-flight set for the next sweep") + + // next block succeeds + require.NoError(t, f.k.SweepExpired(f.ctx)) + + ur, _ = f.k.GetUniversalRead(f.ctx, "0xaa") + require.Equal(t, types.UniversalReadStatus_UNIVERSAL_READ_STATUS_EXPIRED, ur.Status) + require.Len(t, ur.PcTx, 2, "both attempts recorded") + require.Equal(t, "SUCCESS", ur.PcTx[1].Status) + require.Empty(t, collectDueBy(t, f, 100)) +} + +// Retries are bounded, and giving up is recorded as ABORTED rather than EXPIRED: +// the contract never acknowledged the request, so claiming it expired would assert +// a refund that was never credited. +func TestSweepExpired_GivesUpAfterMaxAttempts(t *testing.T) { + f := SetupTest(t) + f.ctx = f.ctx.WithBlockHeight(100) + f.evm.vmErrors = make([]string, keeper.MaxExpiryAttempts) + for i := range f.evm.vmErrors { + f.evm.vmErrors[i] = "RequestAlreadyFulfilled" + } + seedRead(t, f, "0xaa", 50) + + for i := 1; i < keeper.MaxExpiryAttempts; i++ { + require.NoError(t, f.k.SweepExpired(f.ctx)) + ur, _ := f.k.GetUniversalRead(f.ctx, "0xaa") + require.Equal(t, types.UniversalReadStatus_UNIVERSAL_READ_STATUS_PENDING, ur.Status, + "attempt %d must still retry", i) + } + + // the last permitted attempt retires it + require.NoError(t, f.k.SweepExpired(f.ctx)) + + ur, _ := f.k.GetUniversalRead(f.ctx, "0xaa") + require.Equal(t, types.UniversalReadStatus_UNIVERSAL_READ_STATUS_ABORTED, ur.Status, + "not EXPIRED — the contract never accepted it") + require.Contains(t, ur.ErrorMsg, "RequestAlreadyFulfilled", + "the reason is on the record, not only in the logs") + require.Len(t, ur.PcTx, keeper.MaxExpiryAttempts, "every attempt is on the record") + require.Empty(t, collectDueBy(t, f, 100), "left the in-flight set") + + // and it stops consuming sweep slots + before := len(f.evm.calls) + require.NoError(t, f.k.SweepExpired(f.ctx)) + require.Equal(t, before, len(f.evm.calls), "no further attempts") +} + +// The per-block bound caps work, and the backlog drains over later blocks — +// oldest first, since the set is ordered by deadline. +func TestSweepExpired_BoundedAndDrains(t *testing.T) { + f := SetupTest(t) + f.ctx = f.ctx.WithBlockHeight(100_000) + + total := keeper.MaxExpiriesPerBlock + 7 + for i := 0; i < total; i++ { + seedRead(t, f, fmt.Sprintf("0x%x", 0x1000+i), uint64(10+i)) + } + + require.NoError(t, f.k.SweepExpired(f.ctx)) + require.Len(t, f.evm.calls, keeper.MaxExpiriesPerBlock, "capped") + + // the oldest deadlines went first + require.Equal(t, fmt.Sprintf("0x%x", 0x1000), expiredIDs(f)[0]) + + require.NoError(t, f.k.SweepExpired(f.ctx)) + require.Len(t, f.evm.calls, total, "backlog drains on the next block") + + require.Empty(t, collectDueBy(t, f, 100_000)) +} + +func TestSweepExpired_NothingDue(t *testing.T) { + f := SetupTest(t) + f.ctx = f.ctx.WithBlockHeight(10) + seedRead(t, f, "0xaa", 500) + + require.NoError(t, f.k.SweepExpired(f.ctx)) + require.Empty(t, f.evm.calls) + require.Equal(t, []string{"0xaa"}, pendingIDs(t, f)) +} + +func TestSweepExpired_EmptyState(t *testing.T) { + f := SetupTest(t) + f.ctx = f.ctx.WithBlockHeight(100) + require.NoError(t, f.k.SweepExpired(f.ctx)) + require.Empty(t, f.evm.calls) +} + +// Retiring uses the module account and advances its nonce, same as fulfilment. +func TestSweepExpired_UsesModuleNonce(t *testing.T) { + f := SetupTest(t) + f.ctx = f.ctx.WithBlockHeight(100) + require.NoError(t, f.k.ModuleAccountNonce.Set(f.ctx, 5)) + + seedRead(t, f, "0xaa", 10) + seedRead(t, f, "0xbb", 20) + require.NoError(t, f.k.SweepExpired(f.ctx)) + + require.Equal(t, uint64(5), *f.evm.calls[0].nonce) + require.Equal(t, uint64(6), *f.evm.calls[1].nonce, "each call advances it") + require.Equal(t, moduleEVMAddr(), f.evm.calls[0].from) + + n, err := f.k.GetModuleAccountNonce(f.ctx) + require.NoError(t, err) + require.Equal(t, uint64(7), n) +} + +// ABORTED is terminal: it must leave the in-flight set and never be swept again, +// even though the contract may still consider the request pending. +func TestSweepExpired_AbortedIsTerminal(t *testing.T) { + f := SetupTest(t) + f.ctx = f.ctx.WithBlockHeight(100) + f.evm.vmErrors = make([]string, keeper.MaxExpiryAttempts) + for i := range f.evm.vmErrors { + f.evm.vmErrors[i] = "boom" + } + seedRead(t, f, "0xaa", 50) + + for i := 0; i < keeper.MaxExpiryAttempts; i++ { + require.NoError(t, f.k.SweepExpired(f.ctx)) + } + + ur, _ := f.k.GetUniversalRead(f.ctx, "0xaa") + require.Equal(t, types.UniversalReadStatus_UNIVERSAL_READ_STATUS_ABORTED, ur.Status) + + // gone from every in-flight view + require.Empty(t, collectDueBy(t, f, 999)) + require.Empty(t, pendingIDs(t, f)) + _, found := f.k.GetUniversalReadByBallot(f.ctx, ur.BallotKey) + require.False(t, found) + + // but still queryable — this is the state an operator has to find + res, err := f.queryServer.UniversalRead(f.ctx, + &types.QueryUniversalReadRequest{RequestId: "0xaa"}) + require.NoError(t, err) + require.Equal(t, types.UniversalReadStatus_UNIVERSAL_READ_STATUS_ABORTED, res.Read.Status) + require.Contains(t, res.Read.ErrorMsg, "boom") +} + +// A clean fulfilment leaves no error text behind — ErrorMsg is only ever set on a +// path that failed, so its presence is meaningful. +func TestFulfil_SuccessLeavesNoErrorMsg(t *testing.T) { + f := SetupTest(t) + f.ctx = f.ctx.WithBlockHeight(10) + + seedRead(t, f, "0xaa", 500) + key := voteToQuorum(t, f, "0xaa", obs(0x01)) + require.NoError(t, fireTerminal(f, key, uvalidatortypes.BallotStatus_BALLOT_STATUS_PASSED)) + + ur, _ := f.k.GetUniversalRead(f.ctx, "0xaa") + require.Equal(t, types.UniversalReadStatus_UNIVERSAL_READ_STATUS_FULFILLED, ur.Status) + require.Empty(t, ur.ErrorMsg) + for i, p := range ur.PcTx { + require.Equal(t, "SUCCESS", p.Status, "pc_tx[%d]", i) + } +} + +// abortedIDs lists what the operator-facing query returns. +func abortedIDs(t *testing.T, f *testFixture) []string { + t.Helper() + res, err := f.queryServer.AllAbortedReadRequests(f.ctx, + &types.QueryAllAbortedReadRequestsRequest{}) + require.NoError(t, err) + got := make([]string, 0, len(res.Reads)) + for _, r := range res.Reads { + got = append(got, r.Id) + } + return got +} + +// abandon drives one request all the way to ABORTED. +func abandon(t *testing.T, f *testFixture, id string, reason string) { + t.Helper() + seedRead(t, f, id, 50) + for i := 0; i < keeper.MaxExpiryAttempts; i++ { + f.evm.vmErrors = append(f.evm.vmErrors, reason) + require.NoError(t, f.k.SweepExpired(f.ctx)) + } + ur, _ := f.k.GetUniversalRead(f.ctx, id) + require.Equal(t, types.UniversalReadStatus_UNIVERSAL_READ_STATUS_ABORTED, ur.Status) +} + +// Only abandoned reads appear, and they carry the reason. +func TestAllAbortedReadRequests(t *testing.T) { + f := SetupTest(t) + f.ctx = f.ctx.WithBlockHeight(100) + + require.Empty(t, abortedIDs(t, f), "nothing abandoned yet") + + abandon(t, f, "0xaa", "RequestNotYetExpired") + + // a healthy expiry and a live request must not show up + seedRead(t, f, "0xbb", 50) + require.NoError(t, f.k.SweepExpired(f.ctx)) + seedRead(t, f, "0xcc", 9000) + + require.Equal(t, []string{"0xaa"}, abortedIDs(t, f)) + + res, err := f.queryServer.AllAbortedReadRequests(f.ctx, + &types.QueryAllAbortedReadRequestsRequest{}) + require.NoError(t, err) + require.Contains(t, res.Reads[0].ErrorMsg, "RequestNotYetExpired", + "the operator needs the reason, not just the id") + require.Len(t, res.Reads[0].PcTx, keeper.MaxExpiryAttempts) + + // the healthy one settled cleanly + bb, _ := f.k.GetUniversalRead(f.ctx, "0xbb") + require.Equal(t, types.UniversalReadStatus_UNIVERSAL_READ_STATUS_EXPIRED, bb.Status) +} + +// A read that leaves ABORTED — an admin retry that finally lands — drops off the +// list, so the query always reflects what still needs attention. +func TestAllAbortedReadRequests_ClearsOnRecovery(t *testing.T) { + f := SetupTest(t) + f.ctx = f.ctx.WithBlockHeight(100) + + abandon(t, f, "0xaa", "boom") + require.Equal(t, []string{"0xaa"}, abortedIDs(t, f)) + + // recovery: the request finally settles + ur, _ := f.k.GetUniversalRead(f.ctx, "0xaa") + ur.Status = types.UniversalReadStatus_UNIVERSAL_READ_STATUS_EXPIRED + require.NoError(t, f.k.SetUniversalRead(f.ctx, ur)) + + require.Empty(t, abortedIDs(t, f), "no longer needs intervention") +} + +func TestAllAbortedReadRequests_NilRequest(t *testing.T) { + f := SetupTest(t) + _, err := f.queryServer.AllAbortedReadRequests(f.ctx, nil) + require.Error(t, err) +} + +// The retry budget must not be shortened by a failed fulfilment. A fulfil that did +// not settle leaves its PCTx behind and the read in flight, so counting PcTx +// entries would hand exactly those reads fewer expiry attempts than a clean one. +func TestSweepExpired_RetryBudgetIgnoresFulfilAttempts(t *testing.T) { + f := SetupTest(t) + f.ctx = f.ctx.WithBlockHeight(10) + + seedRead(t, f, "0xaa", 50) + key := voteToQuorum(t, f, "0xaa", obs(0x01)) + + // a fulfilment that reverts without settling — leaves a PCTx, stays in flight + f.evm.vmErrors = []string{"execution reverted"} + f.evm.revertData = selector("CallerIsNotUCallbackModule()") + require.NoError(t, fireTerminal(f, key, uvalidatortypes.BallotStatus_BALLOT_STATUS_PASSED)) + + ur, _ := f.k.GetUniversalRead(f.ctx, "0xaa") + require.Len(t, ur.PcTx, 1, "the failed fulfil is on the record; no report followed it") + require.Equal(t, uint32(0), ur.ExpiryAttempts, "but it is not an expiry attempt") + + // now the sweeper takes over, and must get its full budget + f.ctx = f.ctx.WithBlockHeight(100) + f.evm.revertData = nil + for i := 1; i <= keeper.MaxExpiryAttempts; i++ { + f.evm.vmErrors = []string{"boom"} + require.NoError(t, f.k.SweepExpired(f.ctx)) + ur, _ = f.k.GetUniversalRead(f.ctx, "0xaa") + require.Equal(t, uint32(i), ur.ExpiryAttempts, "attempt %d", i) + } + + require.Equal(t, types.UniversalReadStatus_UNIVERSAL_READ_STATUS_ABORTED, ur.Status) + require.Len(t, ur.PcTx, keeper.MaxExpiryAttempts+1, + "one fulfil attempt plus a full expiry budget") +} + +// Both attempts are visible off-chain: a failed fulfil followed by the sweeper's +// expiry leaves an ordered audit trail on one record. +func TestPcTx_RecordsFulfilThenExpiry(t *testing.T) { + f := SetupTest(t) + f.ctx = f.ctx.WithBlockHeight(10) + + seedRead(t, f, "0xaa", 50) + key := voteToQuorum(t, f, "0xaa", obs(0x01)) + + f.evm.vmErrors = []string{"execution reverted"} + f.evm.revertData = selector("CallerIsNotUCallbackModule()") + require.NoError(t, fireTerminal(f, key, uvalidatortypes.BallotStatus_BALLOT_STATUS_PASSED)) + + f.ctx = f.ctx.WithBlockHeight(100) + f.evm.revertData = nil + require.NoError(t, f.k.SweepExpired(f.ctx)) + + ur, _ := f.k.GetUniversalRead(f.ctx, "0xaa") + require.Equal(t, types.UniversalReadStatus_UNIVERSAL_READ_STATUS_EXPIRED, ur.Status) + require.Len(t, ur.PcTx, 2) + require.Equal(t, "FAILED", ur.PcTx[0].Status, "the fulfil attempt") + require.Equal(t, "SUCCESS", ur.PcTx[1].Status, "the expiry that settled it") + require.Equal(t, 0, f.evm.callsTo(types.MethodReportCallbackGas), + "a fulfil that never settled must not be reported") +} diff --git a/x/ucallback/keeper/genesis.go b/x/ucallback/keeper/genesis.go new file mode 100644 index 00000000..b45cf76b --- /dev/null +++ b/x/ucallback/keeper/genesis.go @@ -0,0 +1,67 @@ +package keeper + +import ( + "context" + + "github.com/pushchain/push-chain-node/x/ucallback/types" +) + +// InitGenesis initializes the module's state from a genesis state. +// +// Only UniversalReads is imported. The PendingByExpiry, ReadsByTxHash and +// AbortedReads indexes +// are rebuilt here from the records themselves, via SetUniversalRead — importing +// them separately would allow a genesis file to carry indexes that disagree with +// the records they point at. +func (k *Keeper) InitGenesis(ctx context.Context, data *types.GenesisState) error { + if err := data.Params.Validate(); err != nil { + return err + } + + if err := k.Params.Set(ctx, data.Params); err != nil { + return err + } + + for _, entry := range data.UniversalReads { + if err := k.SetUniversalRead(ctx, entry.Value); err != nil { + return err + } + } + + // Only written when non-zero so a fresh genesis leaves the item unset and + // GetModuleAccountNonce's default applies. + if data.ModuleAccountNonce > 0 { + if err := k.ModuleAccountNonce.Set(ctx, data.ModuleAccountNonce); err != nil { + return err + } + } + + return nil +} + +// ExportGenesis exports the module's state to a genesis state. +func (k *Keeper) ExportGenesis(ctx context.Context) *types.GenesisState { + params, err := k.Params.Get(ctx) + if err != nil { + panic(err) + } + + reads := []types.UniversalReadEntry{} + if err := k.UniversalReads.Walk(ctx, nil, func(key string, value types.UniversalRead) (bool, error) { + reads = append(reads, types.UniversalReadEntry{Key: key, Value: value}) + return false, nil + }); err != nil { + panic(err) + } + + nonce, err := k.GetModuleAccountNonce(ctx) + if err != nil { + panic(err) + } + + return &types.GenesisState{ + Params: params, + UniversalReads: reads, + ModuleAccountNonce: nonce, + } +} diff --git a/x/ucallback/keeper/genesis_test.go b/x/ucallback/keeper/genesis_test.go new file mode 100755 index 00000000..210cd36a --- /dev/null +++ b/x/ucallback/keeper/genesis_test.go @@ -0,0 +1,22 @@ +package keeper_test + +import ( + "testing" + + "github.com/pushchain/push-chain-node/x/ucallback/types" + "github.com/stretchr/testify/require" +) + +func TestGenesis(t *testing.T) { + f := SetupTest(t) + + genesisState := &types.GenesisState{ + Params: types.DefaultParams(), + } + + f.k.InitGenesis(f.ctx, genesisState) + + got := f.k.ExportGenesis(f.ctx) + require.NotNil(t, got) + +} diff --git a/x/ucallback/keeper/ingest.go b/x/ucallback/keeper/ingest.go new file mode 100644 index 00000000..a9b3e4d8 --- /dev/null +++ b/x/ucallback/keeper/ingest.go @@ -0,0 +1,128 @@ +package keeper + +import ( + "context" + "fmt" + "math/big" + "strings" + + sdk "github.com/cosmos/cosmos-sdk/types" + evmtypes "github.com/cosmos/evm/x/vm/types" + + "github.com/pushchain/push-chain-node/x/ucallback/types" + uregistrytypes "github.com/pushchain/push-chain-node/x/uregistry/types" +) + +// IngestReadRequests records a UniversalRead for every ReadRequested event in the +// receipt. +// +// The two-part filter — log.Address must be UniversalCallback, topic0 must be +// ReadRequested — is what makes the decoded event trustworthy. Any contract can +// emit a log with the same topic0; only the system contract's address makes it +// ours. Dropping the address check would let anyone mint read requests. +func (k Keeper) IngestReadRequests(ctx context.Context, receipt *evmtypes.MsgEthereumTxResponse) error { + if receipt == nil || len(receipt.Logs) == 0 { + return nil + } + + sdkCtx := sdk.UnwrapSDKContext(ctx) + callbackAddr := strings.ToLower(uregistrytypes.SYSTEM_CONTRACTS["UNIVERSAL_CALLBACK"].Address) + + for _, lg := range receipt.Logs { + if lg.Removed { + continue + } + if strings.ToLower(lg.Address) != callbackAddr { + continue + } + if len(lg.Topics) == 0 || + !strings.EqualFold(lg.Topics[0], types.ReadRequestedEventSig.Hex()) { + continue + } + + event, err := types.DecodeReadRequestedFromLog(lg) + if err != nil { + return fmt.Errorf("failed to decode ReadRequested (tx %s log %d): %w", + receipt.Hash, lg.Index, err) + } + + if err := k.recordReadRequest(ctx, sdkCtx, event, receipt.Hash, lg.Index); err != nil { + return err + } + } + + return nil +} + +// recordReadRequest writes one decoded event as a PENDING UniversalRead. +func (k Keeper) recordReadRequest( + ctx context.Context, + sdkCtx sdk.Context, + event *types.ReadRequestedEvent, + txHash string, + logIndex uint64, +) error { + // requestId is derived on-chain from an incrementing nonce, so a repeat means + // the same log was replayed rather than a genuine second request. Keep the + // first record: it is the one validators may already be working from. + if k.HasUniversalRead(ctx, event.RequestID) { + k.Logger().Debug("read request already recorded, skipping", + "request_id", event.RequestID, "tx_hash", txHash) + return nil + } + + ur := types.UniversalRead{ + Id: event.RequestID, + Status: types.UniversalReadStatus_UNIVERSAL_READ_STATUS_PENDING, + Request: &types.ReadRequest{ + RequestId: event.RequestID, + DestinationChain: event.DestinationChain(), + Owner: event.Owner, + Query: event.Query, + MinConfirmations: uint32(event.MinConfirmations), + DestinationBlockHeight: event.BlockNumber, + ExpiryBlockHeight: event.ExpiryPushChainHeight, + // Not carried by the event — the height at which we observed it is the + // only honest answer, and it is what expiry is measured against. + CreatedAtHeight: uint64(sdkCtx.BlockHeight()), + CallbackTarget: event.CallbackTarget, + OriginalFunder: event.OriginalFunder, + FeesDeposited: bigOrZero(event.TotalPaid), + MaxFee: bigOrZero(event.MaxFee), + ProtocolFee: bigOrZero(event.ProtocolFee), + CallbackBudget: bigOrZero(event.CallbackBudget), + CallbackGasLimit: event.CallbackGasLimit, + RevertRecipient: event.RevertRecipient, + RequestedTxHash: txHash, + RequestedLogIndex: logIndex, + }, + } + + if err := k.SetUniversalRead(ctx, ur); err != nil { + return fmt.Errorf("failed to record read request %s: %w", event.RequestID, err) + } + + k.Logger().Info("read request recorded", + "request_id", event.RequestID, + "destination_chain", ur.Request.DestinationChain, + "expiry_height", ur.Request.ExpiryBlockHeight, + "tx_hash", txHash, + "log_index", logIndex, + ) + + return nil +} + +// bigOrZero renders a *big.Int as a decimal string, tolerating nil. The proto +// carries these as strings because they are uint256 values that do not fit any +// protobuf integer type. +// +// Takes *big.Int rather than a String()-bearing interface on purpose: a nil +// *big.Int boxed into an interface is not itself nil, so the guard would miss it +// and String() would be called on a nil receiver. +func bigOrZero(v *big.Int) string { + if v == nil { + return "0" + } + return v.String() +} diff --git a/x/ucallback/keeper/ingest_test.go b/x/ucallback/keeper/ingest_test.go new file mode 100644 index 00000000..69517063 --- /dev/null +++ b/x/ucallback/keeper/ingest_test.go @@ -0,0 +1,228 @@ +package keeper_test + +import ( + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" + + evmtypes "github.com/cosmos/evm/x/vm/types" + + "github.com/pushchain/push-chain-node/x/ucallback/types" + uregistrytypes "github.com/pushchain/push-chain-node/x/uregistry/types" +) + +type acct struct { + ChainNamespace string + ChainId string + Owner []byte +} + +type spec struct { + Account acct + Query []byte + MinConfirmations uint16 + BlockNumber uint64 + ExpiryPushChainHeight uint64 + MaxFee *big.Int + RevertRecipient common.Address +} + +// readLog builds a well-formed ReadRequested log emitted by the real system +// contract address. +func readLog(t *testing.T, requestID string, expiry uint64, index uint64) *evmtypes.Log { + t.Helper() + data, err := types.ReadRequestedEventInputs().NonIndexed().Pack(spec{ + Account: acct{ + ChainNamespace: "eip155", + ChainId: "11155111", + Owner: common.FromHex("0x1111111111111111111111111111111111111111"), + }, + Query: common.FromHex("0xdeadbeef"), + MinConfirmations: 6, + BlockNumber: 8_000_000, + ExpiryPushChainHeight: expiry, + MaxFee: big.NewInt(7), + RevertRecipient: common.HexToAddress("0x4444444444444444444444444444444444444444"), + }, + // order follows the event, not intuition: callbackGasLimit precedes the + // three amounts. Packing through ReadRequestedEventInputs keeps this honest. + uint64(250_000), // callbackGasLimit + big.NewInt(99), // totalPaid + big.NewInt(60), // protocolFee + big.NewInt(39), // callbackBudget + ) + require.NoError(t, err) + + return &evmtypes.Log{ + Address: uregistrytypes.SYSTEM_CONTRACTS["UNIVERSAL_CALLBACK"].Address, + Topics: []string{ + types.ReadRequestedEventSig.Hex(), + common.HexToHash(requestID).Hex(), + common.HexToHash("0x2222222222222222222222222222222222222222").Hex(), + common.HexToHash("0x3333333333333333333333333333333333333333").Hex(), + }, + Data: data, + Index: index, + } +} + +func receipt(hash string, logs ...*evmtypes.Log) *evmtypes.MsgEthereumTxResponse { + return &evmtypes.MsgEthereumTxResponse{Hash: hash, Logs: logs} +} + +func TestIngestReadRequests_RecordsPendingRead(t *testing.T) { + f := SetupTest(t) + f.ctx = f.ctx.WithBlockHeight(4242) + + lg := readLog(t, "0xaa", 900_000, 3) + require.NoError(t, f.k.IngestReadRequests(f.ctx, receipt("0xTX", lg))) + + ur, found := f.k.GetUniversalRead(f.ctx, lg.Topics[1]) + require.True(t, found) + require.Equal(t, types.UniversalReadStatus_UNIVERSAL_READ_STATUS_PENDING, ur.Status) + + r := ur.Request + require.Equal(t, "eip155:11155111", r.DestinationChain, "namespace and id joined to CAIP-2") + require.Equal(t, common.FromHex("0x1111111111111111111111111111111111111111"), r.Owner) + require.Equal(t, common.FromHex("0xdeadbeef"), r.Query) + require.Equal(t, uint32(6), r.MinConfirmations) + require.Equal(t, uint64(8_000_000), r.DestinationBlockHeight) + require.Equal(t, uint64(900_000), r.ExpiryBlockHeight) + require.Equal(t, uint64(4242), r.CreatedAtHeight, "taken from the block, not the event") + require.Equal(t, "0xTX", r.RequestedTxHash) + require.Equal(t, uint64(3), r.RequestedLogIndex) + require.Equal(t, "99", r.FeesDeposited, "total paid") + require.Equal(t, "7", r.MaxFee) + + // the fee split arrives intact, and the parts reconstitute the whole + require.Equal(t, "60", r.ProtocolFee) + require.Equal(t, "39", r.CallbackBudget) + require.Equal(t, uint64(250_000), r.CallbackGasLimit) + require.Equal(t, "0x4444444444444444444444444444444444444444", r.RevertRecipient) +} + +// The address filter is the whole trust boundary: topic0 alone is forgeable by +// any contract, so a matching event from elsewhere must be ignored entirely. +func TestIngestReadRequests_IgnoresForeignContract(t *testing.T) { + f := SetupTest(t) + + lg := readLog(t, "0xaa", 900_000, 0) + lg.Address = "0x000000000000000000000000000000000000dEaD" + + require.NoError(t, f.k.IngestReadRequests(f.ctx, receipt("0xTX", lg))) + require.False(t, f.k.HasUniversalRead(f.ctx, lg.Topics[1]), + "a ReadRequested-shaped log from a foreign address must not mint a request") +} + +func TestIngestReadRequests_IgnoresUnrelatedLogs(t *testing.T) { + f := SetupTest(t) + + other := &evmtypes.Log{ + Address: uregistrytypes.SYSTEM_CONTRACTS["UNIVERSAL_CALLBACK"].Address, + Topics: []string{common.HexToHash("0xfeed").Hex()}, + Data: []byte{1, 2, 3}, + } + noTopics := &evmtypes.Log{ + Address: uregistrytypes.SYSTEM_CONTRACTS["UNIVERSAL_CALLBACK"].Address, + } + + require.NoError(t, f.k.IngestReadRequests(f.ctx, receipt("0xTX", other, noTopics))) + require.Empty(t, pendingIDs(t, f)) +} + +func TestIngestReadRequests_SkipsRemovedLogs(t *testing.T) { + f := SetupTest(t) + + lg := readLog(t, "0xaa", 900_000, 0) + lg.Removed = true + + require.NoError(t, f.k.IngestReadRequests(f.ctx, receipt("0xTX", lg))) + require.False(t, f.k.HasUniversalRead(f.ctx, lg.Topics[1])) +} + +// One transaction emitting several ReadRequested logs becomes several independent +// records that still reassemble as a batch. +func TestIngestReadRequests_Batch(t *testing.T) { + f := SetupTest(t) + + a := readLog(t, "0xaa", 900_000, 0) + b := readLog(t, "0xbb", 900_001, 1) + c := readLog(t, "0xcc", 900_002, 2) + + require.NoError(t, f.k.IngestReadRequests(f.ctx, receipt("0xBATCH", a, b, c))) + + res, err := f.queryServer.ReadsByTx(f.ctx, &types.QueryReadsByTxRequest{TxHash: "0xBATCH"}) + require.NoError(t, err) + require.Len(t, res.Reads, 3) + + for _, r := range res.Reads { + require.Equal(t, "0xBATCH", r.Request.RequestedTxHash) + require.Equal(t, types.UniversalReadStatus_UNIVERSAL_READ_STATUS_PENDING, r.Status) + } + // log index is preserved per sibling, so each is individually addressable + require.ElementsMatch(t, []uint64{0, 1, 2}, + []uint64{res.Reads[0].Request.RequestedLogIndex, + res.Reads[1].Request.RequestedLogIndex, + res.Reads[2].Request.RequestedLogIndex}) +} + +// Replaying the same log must not overwrite progress already made on the request. +func TestIngestReadRequests_IsIdempotent(t *testing.T) { + f := SetupTest(t) + + lg := readLog(t, "0xaa", 900_000, 0) + require.NoError(t, f.k.IngestReadRequests(f.ctx, receipt("0xTX", lg))) + + // the request advances + ur, found := f.k.GetUniversalRead(f.ctx, lg.Topics[1]) + require.True(t, found) + ur.Status = types.UniversalReadStatus_UNIVERSAL_READ_STATUS_VOTING + ur.BallotKey = "ballot-1" + require.NoError(t, f.k.SetUniversalRead(f.ctx, ur)) + + // replay + require.NoError(t, f.k.IngestReadRequests(f.ctx, receipt("0xTX", lg))) + + again, found := f.k.GetUniversalRead(f.ctx, lg.Topics[1]) + require.True(t, found) + require.Equal(t, types.UniversalReadStatus_UNIVERSAL_READ_STATUS_VOTING, again.Status, + "replay must not reset an in-flight request to PENDING") + require.Equal(t, "ballot-1", again.BallotKey) +} + +// An undecodable log from our own contract is a bug, not user error. Returning an +// error reverts the EVM tx so the funder keeps their fee rather than paying for a +// request no validator will ever see. +func TestIngestReadRequests_UndecodableIsAnError(t *testing.T) { + f := SetupTest(t) + + lg := readLog(t, "0xaa", 900_000, 0) + lg.Data = lg.Data[:len(lg.Data)/2] + + require.Error(t, f.k.IngestReadRequests(f.ctx, receipt("0xTX", lg))) + require.Empty(t, pendingIDs(t, f)) +} + +func TestIngestReadRequests_EmptyReceipt(t *testing.T) { + f := SetupTest(t) + require.NoError(t, f.k.IngestReadRequests(f.ctx, nil)) + require.NoError(t, f.k.IngestReadRequests(f.ctx, receipt("0xTX"))) + require.Empty(t, pendingIDs(t, f)) +} + +// Ingested reads are immediately visible to validators through the polling query. +func TestIngestReadRequests_VisibleToValidators(t *testing.T) { + f := SetupTest(t) + f.ctx = f.ctx.WithBlockHeight(100) + + live := readLog(t, "0xaa", 500, 0) + dead := readLog(t, "0xbb", 50, 1) + + require.NoError(t, f.k.IngestReadRequests(f.ctx, receipt("0xTX", live, dead))) + + require.Equal(t, []string{live.Topics[1]}, pendingIDs(t, f), + "a request ingested already past its expiry is recorded but never offered") + require.True(t, f.k.HasUniversalRead(f.ctx, dead.Topics[1])) +} diff --git a/x/ucallback/keeper/keeper.go b/x/ucallback/keeper/keeper.go new file mode 100755 index 00000000..967139ce --- /dev/null +++ b/x/ucallback/keeper/keeper.go @@ -0,0 +1,167 @@ +package keeper + +import ( + "context" + "errors" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/ethereum/go-ethereum/common" + + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + + "cosmossdk.io/collections" + storetypes "cosmossdk.io/core/store" + "cosmossdk.io/log" + + "github.com/pushchain/push-chain-node/x/ucallback/types" +) + +type Keeper struct { + cdc codec.BinaryCodec + + logger log.Logger + + // state management + Schema collections.Schema + Params collections.Item[types.Params] + + // UniversalReads is the canonical record for every read request, keyed by + // requestId. Indexes over it are added alongside the lookups they serve, and + // are always derived — never a source of truth. + UniversalReads collections.Map[string, types.UniversalRead] + + // PendingByExpiry holds (expiryHeight, requestId) for reads that have not + // settled — the module's in-flight set. Ordered composite key so the sweeper + // can range-scan by height. + PendingByExpiry collections.KeySet[collections.Pair[uint64, string]] + + // ReadsByTxHash holds (pushTxHash, requestId) so every read emitted by one + // Push transaction can be listed together. + ReadsByTxHash collections.KeySet[collections.Pair[string, string]] + + // AbortedReads holds the ids of reads the chain abandoned. Derived from + // status like the other indexes — see SetUniversalRead. + AbortedReads collections.KeySet[string] + + // ModuleAccountNonce is the EVM nonce of this module's account. x/ucallback + // owns it because it owns the account — UniversalCallback admits only this + // module's address, so nothing else ever sends from it. + ModuleAccountNonce collections.Item[uint64] + + uvalidatorKeeper types.UValidatorKeeper + evmKeeper types.EVMKeeper + accountKeeper types.AccountKeeper + bankKeeper types.BankKeeper + feemarketKeeper types.FeeMarketKeeper + + authority string +} + +// NewKeeper creates a new Keeper instance +func NewKeeper( + cdc codec.BinaryCodec, + storeService storetypes.KVStoreService, + logger log.Logger, + authority string, + uvalidatorKeeper types.UValidatorKeeper, + evmKeeper types.EVMKeeper, + accountKeeper types.AccountKeeper, + bankKeeper types.BankKeeper, + feemarketKeeper types.FeeMarketKeeper, +) Keeper { + logger = logger.With(log.ModuleKey, "x/"+types.ModuleName) + + sb := collections.NewSchemaBuilder(storeService) + + if authority == "" { + authority = authtypes.NewModuleAddress(govtypes.ModuleName).String() + } + + k := Keeper{ + cdc: cdc, + logger: logger, + + Params: collections.NewItem(sb, types.ParamsKey, "params", codec.CollValue[types.Params](cdc)), + + UniversalReads: collections.NewMap( + sb, types.UniversalReadsKey, "universal_reads", + collections.StringKey, codec.CollValue[types.UniversalRead](cdc), + ), + PendingByExpiry: collections.NewKeySet( + sb, types.PendingByExpiryKey, "pending_by_expiry", + collections.PairKeyCodec(collections.Uint64Key, collections.StringKey), + ), + ReadsByTxHash: collections.NewKeySet( + sb, types.ReadsByTxHashKey, "reads_by_tx_hash", + collections.PairKeyCodec(collections.StringKey, collections.StringKey), + ), + + AbortedReads: collections.NewKeySet( + sb, types.AbortedReadsKey, "aborted_reads", collections.StringKey, + ), + + ModuleAccountNonce: collections.NewItem( + sb, types.ModuleAccountNonceKey, types.ModuleAccountNonceName, + collections.Uint64Value, + ), + + uvalidatorKeeper: uvalidatorKeeper, + evmKeeper: evmKeeper, + accountKeeper: accountKeeper, + bankKeeper: bankKeeper, + feemarketKeeper: feemarketKeeper, + authority: authority, + } + + schema, err := sb.Build() + if err != nil { + panic(err) + } + + k.Schema = schema + + return k +} + +func (k Keeper) Logger() log.Logger { + return k.logger +} + +// GetModuleAddress returns the x/ucallback module account's EVM address. +// +// This is the address UniversalCallback's access control admits; the contract +// rejects a call from anything else. Derived from the module name, so it is fixed +// for the life of the chain: 0x07a0258D367A4A4cd9d6E4b7eEE8E7eF491CC519. +func (k Keeper) GetModuleAddress(ctx context.Context) (common.Address, string) { + acc := k.accountKeeper.GetModuleAccount(ctx, types.ModuleName) + var evmAddr common.Address + copy(evmAddr[:], acc.GetAddress().Bytes()) + return evmAddr, evmAddr.Hex() +} + +// GetModuleAccountNonce returns the module account's current EVM nonce, defaulting +// to 0 before the first call is made. +func (k Keeper) GetModuleAccountNonce(ctx context.Context) (uint64, error) { + nonce, err := k.ModuleAccountNonce.Get(ctx) + if err != nil { + if errors.Is(err, collections.ErrNotFound) { + return 0, nil + } + return 0, err + } + return nonce, nil +} + +// IncrementModuleAccountNonce advances the nonce and returns the new value. +func (k Keeper) IncrementModuleAccountNonce(ctx context.Context) (uint64, error) { + nonce, err := k.GetModuleAccountNonce(ctx) + if err != nil { + return 0, err + } + next := nonce + 1 + if err := k.ModuleAccountNonce.Set(ctx, next); err != nil { + return 0, err + } + return next, nil +} diff --git a/x/ucallback/keeper/keeper_test.go b/x/ucallback/keeper/keeper_test.go new file mode 100755 index 00000000..cced8db3 --- /dev/null +++ b/x/ucallback/keeper/keeper_test.go @@ -0,0 +1,164 @@ +package keeper_test + +import ( + sdkmath "cosmossdk.io/math" + "testing" + + "github.com/stretchr/testify/suite" + + "cosmossdk.io/core/address" + "cosmossdk.io/log" + storetypes "cosmossdk.io/store/types" + + cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" + sdkaddress "github.com/cosmos/cosmos-sdk/codec/address" + "github.com/cosmos/cosmos-sdk/runtime" + "github.com/cosmos/cosmos-sdk/testutil/integration" + simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" + sdk "github.com/cosmos/cosmos-sdk/types" + moduletestutil "github.com/cosmos/cosmos-sdk/types/module/testutil" + authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + mintkeeper "github.com/cosmos/cosmos-sdk/x/mint/keeper" + minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" + stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + + "github.com/pushchain/push-chain-node/app" + module "github.com/pushchain/push-chain-node/x/ucallback" + "github.com/pushchain/push-chain-node/x/ucallback/keeper" + "github.com/pushchain/push-chain-node/x/ucallback/types" +) + +var maccPerms = map[string][]string{ + authtypes.FeeCollectorName: nil, + stakingtypes.BondedPoolName: {authtypes.Burner, authtypes.Staking}, + stakingtypes.NotBondedPoolName: {authtypes.Burner, authtypes.Staking}, + minttypes.ModuleName: {authtypes.Minter}, + govtypes.ModuleName: {authtypes.Burner}, +} + +type testFixture struct { + suite.Suite + + ctx sdk.Context + k keeper.Keeper + msgServer types.MsgServer + queryServer types.QueryServer + uvalidator *fakeUValidator + evm *fakeEVM + account *fakeAccount + bank *fakeBank + feemarket *fakeFeeMarket + appModule *module.AppModule + + accountkeeper authkeeper.AccountKeeper + bankkeeper bankkeeper.BaseKeeper + stakingKeeper *stakingkeeper.Keeper + mintkeeper mintkeeper.Keeper + + addrs []sdk.AccAddress + govModAddr string +} + +func SetupTest(t *testing.T) *testFixture { + t.Helper() + f := new(testFixture) + + cfg := sdk.GetConfig() // do not seal, more set later + cfg.SetBech32PrefixForAccount(app.Bech32PrefixAccAddr, app.Bech32PrefixAccPub) + cfg.SetBech32PrefixForValidator(app.Bech32PrefixValAddr, app.Bech32PrefixValPub) + cfg.SetBech32PrefixForConsensusNode(app.Bech32PrefixConsAddr, app.Bech32PrefixConsPub) + cfg.SetCoinType(app.CoinType) + + validatorAddressCodec := sdkaddress.NewBech32Codec(app.Bech32PrefixValAddr) + accountAddressCodec := sdkaddress.NewBech32Codec(app.Bech32PrefixAccAddr) + consensusAddressCodec := sdkaddress.NewBech32Codec(app.Bech32PrefixConsAddr) + + // Base setup + logger := log.NewTestLogger(t) + encCfg := moduletestutil.MakeTestEncodingConfig() + + f.govModAddr = authtypes.NewModuleAddress(govtypes.ModuleName).String() + f.addrs = simtestutil.CreateIncrementalAccounts(3) + + keys := storetypes.NewKVStoreKeys(authtypes.ModuleName, banktypes.ModuleName, stakingtypes.ModuleName, minttypes.ModuleName, types.ModuleName) + f.ctx = sdk.NewContext(integration.CreateMultiStore(keys, logger), cmtproto.Header{}, false, logger) + + // Register SDK modules. + registerBaseSDKModules(logger, f, encCfg, keys, accountAddressCodec, validatorAddressCodec, consensusAddressCodec) + + // Setup Keeper. + f.uvalidator = newFakeUValidator() + f.evm = &fakeEVM{} + f.account = &fakeAccount{} + f.bank = newFakeBank() + // UniversalCallback holds escrowed callback budgets; fund it so the take-and-burn + // step has something to draw on. + f.bank.contractBalance = sdkmath.NewInt(1_000_000_000_000_000_000) + // 1 gwei — every gas figure in tests prices at exactly gas × 1e9. + f.feemarket = &fakeFeeMarket{baseFee: sdkmath.LegacyNewDec(1_000_000_000)} + f.k = keeper.NewKeeper(encCfg.Codec, runtime.NewKVStoreService(keys[types.ModuleName]), logger, f.govModAddr, + f.uvalidator, f.evm, f.account, f.bank, f.feemarket) + f.msgServer = keeper.NewMsgServerImpl(f.k) + f.queryServer = keeper.NewQuerier(f.k) + f.appModule = module.NewAppModule(encCfg.Codec, f.k) + + return f +} + +func registerModuleInterfaces(encCfg moduletestutil.TestEncodingConfig) { + authtypes.RegisterInterfaces(encCfg.InterfaceRegistry) + stakingtypes.RegisterInterfaces(encCfg.InterfaceRegistry) + banktypes.RegisterInterfaces(encCfg.InterfaceRegistry) + minttypes.RegisterInterfaces(encCfg.InterfaceRegistry) + + types.RegisterInterfaces(encCfg.InterfaceRegistry) +} + +func registerBaseSDKModules( + logger log.Logger, + f *testFixture, + encCfg moduletestutil.TestEncodingConfig, + keys map[string]*storetypes.KVStoreKey, + ac address.Codec, + validator address.Codec, + consensus address.Codec, +) { + registerModuleInterfaces(encCfg) + + // Auth Keeper. + f.accountkeeper = authkeeper.NewAccountKeeper( + encCfg.Codec, runtime.NewKVStoreService(keys[authtypes.StoreKey]), + authtypes.ProtoBaseAccount, + maccPerms, + ac, app.Bech32PrefixAccAddr, + f.govModAddr, + ) + + // Bank Keeper. + f.bankkeeper = bankkeeper.NewBaseKeeper( + encCfg.Codec, runtime.NewKVStoreService(keys[banktypes.StoreKey]), + f.accountkeeper, + nil, + f.govModAddr, logger, + ) + + // Staking Keeper. + f.stakingKeeper = stakingkeeper.NewKeeper( + encCfg.Codec, runtime.NewKVStoreService(keys[stakingtypes.StoreKey]), + f.accountkeeper, f.bankkeeper, f.govModAddr, + validator, + consensus, + ) + + // Mint Keeper. + f.mintkeeper = mintkeeper.NewKeeper( + encCfg.Codec, runtime.NewKVStoreService(keys[minttypes.StoreKey]), + f.stakingKeeper, f.accountkeeper, f.bankkeeper, + authtypes.FeeCollectorName, f.govModAddr, + ) +} diff --git a/x/ucallback/keeper/lifecycle_test.go b/x/ucallback/keeper/lifecycle_test.go new file mode 100644 index 00000000..b393a27e --- /dev/null +++ b/x/ucallback/keeper/lifecycle_test.go @@ -0,0 +1,133 @@ +package keeper_test + +import ( + "testing" + + sdkmath "cosmossdk.io/math" + "github.com/stretchr/testify/require" + + "github.com/pushchain/push-chain-node/x/ucallback/keeper" + "github.com/pushchain/push-chain-node/x/ucallback/types" + uvalidatortypes "github.com/pushchain/push-chain-node/x/uvalidator/types" +) + +// End-to-end through the real path: an EVM log becomes a record, validators poll +// and vote it to quorum, the ballot hook fulfils, and the consumed gas is reported +// and burned. Each stage is driven by the same entry point production uses. +func TestLifecycle_IngestToBurn(t *testing.T) { + f := SetupTest(t) + f.ctx = f.ctx.WithBlockHeight(100) + v := seedVoters(t, f, 4) + + // ── ingest ── + lg := readLog(t, "0xaa", 5_000, 0) + require.NoError(t, f.k.IngestReadRequests(f.ctx, receipt("0xTX", lg))) + + id := lg.Topics[1] + ur, found := f.k.GetUniversalRead(f.ctx, id) + require.True(t, found) + require.Equal(t, types.UniversalReadStatus_UNIVERSAL_READ_STATUS_PENDING, ur.Status) + require.Equal(t, uint64(250_000), ur.Request.CallbackGasLimit) + require.Equal(t, "39", ur.Request.CallbackBudget) + + // ── validators poll ── + require.Equal(t, []string{id}, pendingIDs(t, f), "offered for observation") + + // the log's budget of 39 wei cannot cover 250k gas at 1 gwei, so fund it + ur.Request.CallbackBudget = "1000000000000000000" + require.NoError(t, f.k.SetUniversalRead(f.ctx, ur)) + + // ── vote to quorum ── + for i := 0; i < 2; i++ { + finalized, err := f.k.VoteReadResult(f.ctx, v[i], id, obs(0x42)) + require.NoError(t, err) + require.False(t, finalized) + } + finalized, err := f.k.VoteReadResult(f.ctx, v[2], id, obs(0x42)) + require.NoError(t, err) + require.True(t, finalized, "3 of 4 carries it") + + // ── the ballot hook fulfils and settles ── + ur, _ = f.k.GetUniversalRead(f.ctx, id) + require.NoError(t, fireTerminal(f, ur.BallotKey, + uvalidatortypes.BallotStatus_BALLOT_STATUS_PASSED)) + + require.Equal(t, 1, f.evm.callsTo(types.MethodFulfillExternalCallback)) + require.Equal(t, 1, f.evm.callsTo(types.MethodReportCallbackGas)) + + want := sdkmath.NewInt(21_000).Mul(sdkmath.NewInt(1_000_000_000)) + require.Equal(t, want, f.bank.burned, "gasUsed × baseFee destroyed") + + // ── final state ── + done, _ := f.k.GetUniversalRead(f.ctx, id) + require.Equal(t, types.UniversalReadStatus_UNIVERSAL_READ_STATUS_FULFILLED, done.Status) + require.Equal(t, []byte{0x42}, done.Result.ResultData) + require.Empty(t, done.ErrorMsg) + require.Len(t, done.PcTx, 2, "the fulfil and the report") + + require.Empty(t, pendingIDs(t, f), "no longer offered") + require.Empty(t, collectDueBy(t, f, 9_999), "and out of the sweeper's reach") + + // the sweeper must not touch a fulfilled read even long past its deadline + f.ctx = f.ctx.WithBlockHeight(50_000) + before := len(f.evm.calls) + require.NoError(t, f.k.SweepExpired(f.ctx)) + require.Equal(t, before, len(f.evm.calls)) +} + +// The other terminal path end-to-end: nobody votes, the deadline passes, the +// sweeper expires it and nothing is burned. +func TestLifecycle_IngestToExpiry(t *testing.T) { + f := SetupTest(t) + f.ctx = f.ctx.WithBlockHeight(100) + + lg := readLog(t, "0xaa", 200, 0) + require.NoError(t, f.k.IngestReadRequests(f.ctx, receipt("0xTX", lg))) + id := lg.Topics[1] + + f.ctx = f.ctx.WithBlockHeight(300) // past the deadline + require.NoError(t, f.k.SweepExpired(f.ctx)) + + ur, _ := f.k.GetUniversalRead(f.ctx, id) + require.Equal(t, types.UniversalReadStatus_UNIVERSAL_READ_STATUS_EXPIRED, ur.Status) + require.Equal(t, uint32(1), ur.ExpiryAttempts) + require.Equal(t, 1, f.evm.callsTo(types.MethodExpireExternalRead)) + require.Equal(t, 0, f.evm.callsTo(types.MethodReportCallbackGas), "nothing to report") + require.True(t, f.bank.burned.IsZero(), "an unexecuted callback burns nothing") +} + +// An underfunded read runs the whole way through without ever touching the +// contract, and its reason survives onto the expired record. +func TestLifecycle_UnderfundedExpiresWithReason(t *testing.T) { + f := SetupTest(t) + f.ctx = f.ctx.WithBlockHeight(100) + v := seedVoters(t, f, 4) + + // budget of 39 wei against a 250k gas limit — nowhere near enough + lg := readLog(t, "0xaa", 500, 0) + require.NoError(t, f.k.IngestReadRequests(f.ctx, receipt("0xTX", lg))) + id := lg.Topics[1] + + for i := 0; i < 3; i++ { + _, err := f.k.VoteReadResult(f.ctx, v[i], id, obs(0x01)) + require.NoError(t, err) + } + ur, _ := f.k.GetUniversalRead(f.ctx, id) + require.NoError(t, fireTerminal(f, ur.BallotKey, + uvalidatortypes.BallotStatus_BALLOT_STATUS_PASSED)) + + require.Equal(t, 0, f.evm.callsTo(types.MethodFulfillExternalCallback), + "never executed") + ur, _ = f.k.GetUniversalRead(f.ctx, id) + require.Equal(t, keeper.ErrBudgetTooSmall, ur.ErrorMsg) + + // and the sweeper still retires it, refunding the whole budget + f.ctx = f.ctx.WithBlockHeight(600) + require.NoError(t, f.k.SweepExpired(f.ctx)) + + ur, _ = f.k.GetUniversalRead(f.ctx, id) + require.Equal(t, types.UniversalReadStatus_UNIVERSAL_READ_STATUS_EXPIRED, ur.Status) + require.Equal(t, keeper.ErrBudgetTooSmall, ur.ErrorMsg, + "the reason it was never fulfilled survives onto the expired record") + require.True(t, f.bank.burned.IsZero()) +} diff --git a/x/ucallback/keeper/msg_retry_expiry_test.go b/x/ucallback/keeper/msg_retry_expiry_test.go new file mode 100644 index 00000000..09c32d8c --- /dev/null +++ b/x/ucallback/keeper/msg_retry_expiry_test.go @@ -0,0 +1,114 @@ +package keeper_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/pushchain/push-chain-node/x/ucallback/keeper" + "github.com/pushchain/push-chain-node/x/ucallback/types" +) + +func retry(f *testFixture, signer, id string) (*types.MsgRetryReadExpiryResponse, error) { + return f.msgServer.RetryReadExpiry(f.ctx, &types.MsgRetryReadExpiry{ + Signer: signer, RequestId: id, + }) +} + +// The whole point: an abandoned read can be settled after the fact, which is +// otherwise impossible — the sweeper skips ABORTED and the contract admits only +// this module. +func TestRetryReadExpiry_SettlesAbandonedRead(t *testing.T) { + f := SetupTest(t) + f.ctx = f.ctx.WithBlockHeight(100) + + abandon(t, f, "0xaa", "RequestNotYetExpired") + require.Equal(t, []string{"0xaa"}, abortedIDs(t, f)) + callsBefore := len(f.evm.calls) + + // the underlying problem is fixed; the contract now accepts it + res, err := retry(f, f.uvalidator.admin, "0xaa") + require.NoError(t, err) + require.True(t, res.Settled) + + require.Len(t, f.evm.calls, callsBefore+1, "exactly one more attempt") + + ur, _ := f.k.GetUniversalRead(f.ctx, "0xaa") + require.Equal(t, types.UniversalReadStatus_UNIVERSAL_READ_STATUS_EXPIRED, ur.Status) + require.Len(t, ur.PcTx, keeper.MaxExpiryAttempts+1, "the retry is on the record too") + require.Equal(t, "SUCCESS", ur.PcTx[len(ur.PcTx)-1].Status) + + require.Empty(t, abortedIDs(t, f), "off the intervention list") +} + +// A failed retry buys one attempt, not a fresh budget — the record stays ABORTED +// with the newest reason. +func TestRetryReadExpiry_FailureStaysAborted(t *testing.T) { + f := SetupTest(t) + f.ctx = f.ctx.WithBlockHeight(100) + + abandon(t, f, "0xaa", "first reason") + + f.evm.vmErrors = []string{"still broken"} + res, err := retry(f, f.uvalidator.admin, "0xaa") + require.NoError(t, err) + require.False(t, res.Settled) + + ur, _ := f.k.GetUniversalRead(f.ctx, "0xaa") + require.Equal(t, types.UniversalReadStatus_UNIVERSAL_READ_STATUS_ABORTED, ur.Status) + require.Equal(t, "still broken", ur.ErrorMsg, "reason refreshed") + require.Len(t, ur.PcTx, keeper.MaxExpiryAttempts+1) + require.Equal(t, []string{"0xaa"}, abortedIDs(t, f), "still needs intervention") + + // and it can be retried again later + res, err = retry(f, f.uvalidator.admin, "0xaa") + require.NoError(t, err) + require.True(t, res.Settled) +} + +func TestRetryReadExpiry_RejectsNonAdmin(t *testing.T) { + f := SetupTest(t) + f.ctx = f.ctx.WithBlockHeight(100) + abandon(t, f, "0xaa", "boom") + callsBefore := len(f.evm.calls) + + _, err := retry(f, "push1nottheadmin", "0xaa") + require.ErrorContains(t, err, "invalid admin") + require.Len(t, f.evm.calls, callsBefore, "no contract call from a non-admin") + + ur, _ := f.k.GetUniversalRead(f.ctx, "0xaa") + require.Equal(t, types.UniversalReadStatus_UNIVERSAL_READ_STATUS_ABORTED, ur.Status) +} + +// Only ABORTED is retryable. Anything else either settled cleanly or is still +// moving, and re-running expiry would close a request the chain has no business +// closing. +func TestRetryReadExpiry_RejectsNonAbortedStatuses(t *testing.T) { + f := SetupTest(t) + f.ctx = f.ctx.WithBlockHeight(100) + + for _, st := range []types.UniversalReadStatus{ + types.UniversalReadStatus_UNIVERSAL_READ_STATUS_PENDING, + types.UniversalReadStatus_UNIVERSAL_READ_STATUS_VOTING, + types.UniversalReadStatus_UNIVERSAL_READ_STATUS_FULFILLED, + types.UniversalReadStatus_UNIVERSAL_READ_STATUS_EXPIRED, + types.UniversalReadStatus_UNIVERSAL_READ_STATUS_FAILED, + } { + id := "0x" + st.String() + require.NoError(t, f.k.SetUniversalRead(f.ctx, newRead(id, "0xTX", 500, st))) + + _, err := retry(f, f.uvalidator.admin, id) + require.ErrorContains(t, err, "only ABORTED", "status %s", st) + } + require.Empty(t, f.evm.calls) +} + +func TestRetryReadExpiry_Rejects(t *testing.T) { + f := SetupTest(t) + + _, err := retry(f, f.uvalidator.admin, "0xmissing") + require.ErrorContains(t, err, "not found") + + _, err = retry(f, f.uvalidator.admin, "") + require.ErrorContains(t, err, "request_id is required") +} diff --git a/x/ucallback/keeper/msg_server.go b/x/ucallback/keeper/msg_server.go new file mode 100755 index 00000000..eff45dae --- /dev/null +++ b/x/ucallback/keeper/msg_server.go @@ -0,0 +1,120 @@ +package keeper + +import ( + "context" + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + + "cosmossdk.io/errors" + "github.com/pushchain/push-chain-node/x/ucallback/types" +) + +type msgServer struct { + k Keeper +} + +var _ types.MsgServer = msgServer{} + +// NewMsgServerImpl returns an implementation of the module MsgServer interface. +func NewMsgServerImpl(keeper Keeper) types.MsgServer { + return &msgServer{k: keeper} +} + +func (ms msgServer) UpdateParams(ctx context.Context, msg *types.MsgUpdateParams) (*types.MsgUpdateParamsResponse, error) { + if ms.k.authority != msg.Authority { + return nil, errors.Wrapf(govtypes.ErrInvalidSigner, "invalid authority; expected %s, got %s", ms.k.authority, msg.Authority) + } + + return nil, ms.k.Params.Set(ctx, msg.Params) +} + +// VoteReadResult implements types.MsgServer. +// +// Eligibility is checked here rather than in the keeper: bonded-and-not-tombstoned +// is a property of the signer, and the same two guards front x/uexecutor's vote +// handlers. A validator that has been slashed out must not keep steering ballots. +func (ms msgServer) VoteReadResult(ctx context.Context, msg *types.MsgVoteReadResult) (*types.MsgVoteReadResultResponse, error) { + if msg.Result == nil { + return nil, fmt.Errorf("result is required") + } + + signerAccAddr, err := sdk.AccAddressFromBech32(msg.Signer) + if err != nil { + return nil, fmt.Errorf("invalid signer address: %w", err) + } + + isBonded, err := ms.k.uvalidatorKeeper.IsBondedUniversalValidator(ctx, msg.Signer) + if err != nil { + return nil, fmt.Errorf("failed to check bonded status for signer %s: %w", msg.Signer, err) + } + if !isBonded { + return nil, fmt.Errorf("universal validator for signer %s is not bonded", msg.Signer) + } + + isTombstoned, err := ms.k.uvalidatorKeeper.IsTombstonedUniversalValidator(ctx, msg.Signer) + if err != nil { + return nil, fmt.Errorf("failed to check tombstoned status for signer %s: %w", msg.Signer, err) + } + if isTombstoned { + return nil, fmt.Errorf("universal validator for signer %s is tombstoned", msg.Signer) + } + + finalized, err := ms.k.VoteReadResult(ctx, sdk.ValAddress(signerAccAddr), msg.RequestId, msg.Result) + if err != nil { + return nil, err + } + + return &types.MsgVoteReadResultResponse{Finalized: finalized}, nil +} + +// RetryReadExpiry implements types.MsgServer — the admin escape hatch. +// +// Only reaches records already at ABORTED, which is a state nothing else can leave: +// the sweeper skips it (terminal, so out of PendingByExpiry) and the contract's +// expireExternalRead admits only this module. Without this path the funder's refund +// stays uncredited permanently. +func (ms msgServer) RetryReadExpiry(ctx context.Context, msg *types.MsgRetryReadExpiry) (*types.MsgRetryReadExpiryResponse, error) { + ms.k.Logger().Info("msg: RetryReadExpiry", "signer", msg.Signer, "request_id", msg.RequestId) + + admin, err := ms.k.uvalidatorKeeper.GetAdmin(ctx) + if err != nil { + return nil, errors.Wrap(err, "failed to read uvalidator admin") + } + if admin != msg.Signer { + return nil, errors.Wrapf(govtypes.ErrInvalidSigner, + "invalid admin; expected %s, got %s", admin, msg.Signer) + } + + if msg.RequestId == "" { + return nil, fmt.Errorf("request_id is required") + } + + ur, found := ms.k.GetUniversalRead(ctx, msg.RequestId) + if !found { + return nil, fmt.Errorf("read request not found: %s", msg.RequestId) + } + + // Deliberately narrow. Any other status either settled cleanly or is still + // moving on its own, and re-running expiry on it would call the contract for a + // request the chain has no business closing. + if ur.Status != types.UniversalReadStatus_UNIVERSAL_READ_STATUS_ABORTED { + return nil, fmt.Errorf("read request %s is %s, only ABORTED requests can be retried", + msg.RequestId, ur.Status) + } + + if err := ms.k.ExpireRead(sdk.UnwrapSDKContext(ctx), ur); err != nil { + return nil, err + } + + // ExpireRead leaves it EXPIRED on success and back at ABORTED on failure, with + // ErrorMsg refreshed either way. + after, _ := ms.k.GetUniversalRead(ctx, msg.RequestId) + settled := after.Status == types.UniversalReadStatus_UNIVERSAL_READ_STATUS_EXPIRED + + ms.k.Logger().Info("admin retry of read expiry", + "request_id", msg.RequestId, "settled", settled, "status", after.Status.String()) + + return &types.MsgRetryReadExpiryResponse{Settled: settled}, nil +} diff --git a/x/ucallback/keeper/msg_server_test.go b/x/ucallback/keeper/msg_server_test.go new file mode 100755 index 00000000..87fb2088 --- /dev/null +++ b/x/ucallback/keeper/msg_server_test.go @@ -0,0 +1,56 @@ +package keeper_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/pushchain/push-chain-node/x/ucallback/types" +) + +func TestParams(t *testing.T) { + f := SetupTest(t) + require := require.New(t) + + testCases := []struct { + name string + request *types.MsgUpdateParams + err bool + }{ + { + name: "fail; invalid authority", + request: &types.MsgUpdateParams{ + Authority: f.addrs[0].String(), + Params: types.DefaultParams(), + }, + err: true, + }, + { + name: "success", + request: &types.MsgUpdateParams{ + Authority: f.govModAddr, + Params: types.DefaultParams(), + }, + err: false, + }, + } + + for _, tc := range testCases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + _, err := f.msgServer.UpdateParams(f.ctx, tc.request) + + if tc.err { + require.Error(err) + } else { + require.NoError(err) + + r, err := f.queryServer.Params(f.ctx, &types.QueryParamsRequest{}) + require.NoError(err) + + require.EqualValues(&tc.request.Params, r.Params) + } + + }) + } +} diff --git a/x/ucallback/keeper/query_server.go b/x/ucallback/keeper/query_server.go new file mode 100755 index 00000000..3f437495 --- /dev/null +++ b/x/ucallback/keeper/query_server.go @@ -0,0 +1,150 @@ +package keeper + +import ( + "context" + + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + "cosmossdk.io/collections" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/query" + + "github.com/pushchain/push-chain-node/x/ucallback/types" +) + +var _ types.QueryServer = Querier{} + +type Querier struct { + Keeper +} + +func NewQuerier(keeper Keeper) Querier { + return Querier{Keeper: keeper} +} + +func (k Querier) Params(c context.Context, req *types.QueryParamsRequest) (*types.QueryParamsResponse, error) { + ctx := sdk.UnwrapSDKContext(c) + + p, err := k.Keeper.Params.Get(ctx) + if err != nil { + return nil, err + } + + return &types.QueryParamsResponse{Params: &p}, nil +} + +// AllPendingReadRequests implements types.QueryServer. +// +// Paginates the in-flight set (PendingByExpiry), which already excludes settled +// reads. Requests whose expiry height has passed are filtered out here too, rather +// than waiting for the sweeper to retire them: a validator that picked one up would +// spend a destination-chain read on work the contract may no longer accept. That +// makes the visible set correct regardless of how often the sweeper runs. +func (k Querier) AllPendingReadRequests(goCtx context.Context, req *types.QueryAllPendingReadRequestsRequest) (*types.QueryAllPendingReadRequestsResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "invalid request") + } + ctx := sdk.UnwrapSDKContext(goCtx) + height := uint64(ctx.BlockHeight()) + + reads, pageRes, err := query.CollectionFilteredPaginate( + ctx, k.Keeper.PendingByExpiry, req.Pagination, + func(key collections.Pair[uint64, string], _ collections.NoValue) (bool, error) { + return key.K1() > height, nil + }, + func(key collections.Pair[uint64, string], _ collections.NoValue) (types.UniversalRead, error) { + ur, found := k.Keeper.GetUniversalRead(ctx, key.K2()) + if !found { + // index entry with no record — skip rather than fail the page + return types.UniversalRead{}, nil + } + return ur, nil + }, + ) + if err != nil { + return nil, status.Error(codes.Internal, err.Error()) + } + + return &types.QueryAllPendingReadRequestsResponse{ + Reads: reads, + Pagination: pageRes, + }, nil +} + +// UniversalRead implements types.QueryServer. +// +// Serves a read at any point in its lifecycle, settled or not — this is the +// endpoint for "what happened to my request", so it must not filter the way +// AllPendingReadRequests does. +func (k Querier) UniversalRead(goCtx context.Context, req *types.QueryUniversalReadRequest) (*types.QueryUniversalReadResponse, error) { + if req == nil || req.RequestId == "" { + return nil, status.Error(codes.InvalidArgument, "request_id is required") + } + ctx := sdk.UnwrapSDKContext(goCtx) + + ur, found := k.Keeper.GetUniversalRead(ctx, req.RequestId) + if !found { + return nil, status.Errorf(codes.NotFound, "no read request with id %s", req.RequestId) + } + + return &types.QueryUniversalReadResponse{Read: ur}, nil +} + +// ReadsByTx implements types.QueryServer. +// +// Returns every read a single Push transaction requested, settled or not. Batches +// are the reason this exists: one transaction can emit several ReadRequested logs, +// each becoming an independent record that settles on its own schedule. +// +// Unpaginated by design — the fan-out is bounded by what fits in one transaction. +func (k Querier) ReadsByTx(goCtx context.Context, req *types.QueryReadsByTxRequest) (*types.QueryReadsByTxResponse, error) { + if req == nil || req.TxHash == "" { + return nil, status.Error(codes.InvalidArgument, "tx_hash is required") + } + ctx := sdk.UnwrapSDKContext(goCtx) + + reads := []types.UniversalRead{} + if err := k.Keeper.IterateReadsByTxHash(ctx, req.TxHash, func(ur types.UniversalRead) bool { + reads = append(reads, ur) + return true + }); err != nil { + return nil, status.Error(codes.Internal, err.Error()) + } + + return &types.QueryReadsByTxResponse{Reads: reads}, nil +} + +// AllAbortedReadRequests implements types.QueryServer. +// +// Paginates the AbortedReads index rather than filtering UniversalReads. Abandoned +// reads should be rare, so a status filter over the full history could walk every +// read the chain has ever seen just to fill one page — a soft DoS on a public +// endpoint. The index holds only the abandoned ones. +func (k Querier) AllAbortedReadRequests(goCtx context.Context, req *types.QueryAllAbortedReadRequestsRequest) (*types.QueryAllAbortedReadRequestsResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "invalid request") + } + ctx := sdk.UnwrapSDKContext(goCtx) + + reads, pageRes, err := query.CollectionPaginate( + ctx, k.Keeper.AbortedReads, req.Pagination, + func(requestID string, _ collections.NoValue) (types.UniversalRead, error) { + ur, found := k.Keeper.GetUniversalRead(ctx, requestID) + if !found { + // index entry with no record — skip rather than fail the page + return types.UniversalRead{}, nil + } + return ur, nil + }, + ) + if err != nil { + return nil, status.Error(codes.Internal, err.Error()) + } + + return &types.QueryAllAbortedReadRequestsResponse{ + Reads: reads, + Pagination: pageRes, + }, nil +} diff --git a/x/ucallback/keeper/query_server_test.go b/x/ucallback/keeper/query_server_test.go new file mode 100644 index 00000000..b16c06d7 --- /dev/null +++ b/x/ucallback/keeper/query_server_test.go @@ -0,0 +1,131 @@ +package keeper_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/pushchain/push-chain-node/x/ucallback/types" +) + +func pendingIDs(t *testing.T, f *testFixture) []string { + t.Helper() + res, err := f.queryServer.AllPendingReadRequests(f.ctx, + &types.QueryAllPendingReadRequestsRequest{}) + require.NoError(t, err) + got := make([]string, 0, len(res.Reads)) + for _, r := range res.Reads { + got = append(got, r.Id) + } + return got +} + +// Only unsettled reads are listed. +func TestAllPendingReadRequests_ExcludesSettled(t *testing.T) { + f := SetupTest(t) + + require.NoError(t, f.k.SetUniversalRead(f.ctx, + newRead("0xpending", "0xTX", 500, types.UniversalReadStatus_UNIVERSAL_READ_STATUS_PENDING))) + require.NoError(t, f.k.SetUniversalRead(f.ctx, + newRead("0xvoting", "0xTX", 500, types.UniversalReadStatus_UNIVERSAL_READ_STATUS_VOTING))) + require.NoError(t, f.k.SetUniversalRead(f.ctx, + newRead("0xdone", "0xTX", 500, types.UniversalReadStatus_UNIVERSAL_READ_STATUS_FULFILLED))) + + require.ElementsMatch(t, []string{"0xpending", "0xvoting"}, pendingIDs(t, f)) +} + +// A read past its expiry height is withheld even though the sweeper has not run, +// so validators never pick up work that can no longer be fulfilled in time. +func TestAllPendingReadRequests_WithholdsExpired(t *testing.T) { + f := SetupTest(t) + + f.ctx = f.ctx.WithBlockHeight(100) + + require.NoError(t, f.k.SetUniversalRead(f.ctx, + newRead("0xexpired", "0xTX", 50, types.UniversalReadStatus_UNIVERSAL_READ_STATUS_PENDING))) + require.NoError(t, f.k.SetUniversalRead(f.ctx, + newRead("0xatheight", "0xTX", 100, types.UniversalReadStatus_UNIVERSAL_READ_STATUS_PENDING))) + require.NoError(t, f.k.SetUniversalRead(f.ctx, + newRead("0xlive", "0xTX", 150, types.UniversalReadStatus_UNIVERSAL_READ_STATUS_PENDING))) + + // still unsettled in state — the filter is at read time, not a mutation + require.True(t, f.k.HasUniversalRead(f.ctx, "0xexpired")) + + require.Equal(t, []string{"0xlive"}, pendingIDs(t, f), + "expiry height is exclusive: a read expiring at the current height is already too late") +} + +func TestAllPendingReadRequests_Empty(t *testing.T) { + f := SetupTest(t) + require.Empty(t, pendingIDs(t, f)) +} + +func TestAllPendingReadRequests_NilRequest(t *testing.T) { + f := SetupTest(t) + _, err := f.queryServer.AllPendingReadRequests(f.ctx, nil) + require.Error(t, err) +} + +// A read is served at any lifecycle stage — this endpoint answers "what happened +// to my request", so unlike the pending list it must not filter. +func TestUniversalRead_ServesSettledAndExpired(t *testing.T) { + f := SetupTest(t) + f.ctx = f.ctx.WithBlockHeight(100) + + for id, st := range map[string]types.UniversalReadStatus{ + "0xpending": types.UniversalReadStatus_UNIVERSAL_READ_STATUS_PENDING, + "0xdone": types.UniversalReadStatus_UNIVERSAL_READ_STATUS_FULFILLED, + "0xgone": types.UniversalReadStatus_UNIVERSAL_READ_STATUS_EXPIRED, + } { + require.NoError(t, f.k.SetUniversalRead(f.ctx, newRead(id, "0xTX", 50, st))) + } + + for _, id := range []string{"0xpending", "0xdone", "0xgone"} { + res, err := f.queryServer.UniversalRead(f.ctx, + &types.QueryUniversalReadRequest{RequestId: id}) + require.NoError(t, err, id) + require.Equal(t, id, res.Read.Id) + } + + // ...even though only one of them is visible to validators + require.Empty(t, pendingIDs(t, f)) +} + +func TestUniversalRead_NotFound(t *testing.T) { + f := SetupTest(t) + + _, err := f.queryServer.UniversalRead(f.ctx, + &types.QueryUniversalReadRequest{RequestId: "0xmissing"}) + require.Error(t, err) + + _, err = f.queryServer.UniversalRead(f.ctx, &types.QueryUniversalReadRequest{}) + require.Error(t, err, "empty request_id is rejected, not treated as not-found") +} + +// The batch view returns siblings regardless of how each one settled. +func TestReadsByTx_ReturnsWholeBatch(t *testing.T) { + f := SetupTest(t) + + require.NoError(t, f.k.SetUniversalRead(f.ctx, + newRead("0xaaa", "0xBATCH", 500, types.UniversalReadStatus_UNIVERSAL_READ_STATUS_PENDING))) + require.NoError(t, f.k.SetUniversalRead(f.ctx, + newRead("0xbbb", "0xBATCH", 500, types.UniversalReadStatus_UNIVERSAL_READ_STATUS_FULFILLED))) + require.NoError(t, f.k.SetUniversalRead(f.ctx, + newRead("0xccc", "0xOTHER", 500, types.UniversalReadStatus_UNIVERSAL_READ_STATUS_PENDING))) + + res, err := f.queryServer.ReadsByTx(f.ctx, &types.QueryReadsByTxRequest{TxHash: "0xBATCH"}) + require.NoError(t, err) + ids := []string{} + for _, r := range res.Reads { + ids = append(ids, r.Id) + } + require.ElementsMatch(t, []string{"0xaaa", "0xbbb"}, ids) + + // an unknown tx is an empty batch, not an error + res, err = f.queryServer.ReadsByTx(f.ctx, &types.QueryReadsByTxRequest{TxHash: "0xNOPE"}) + require.NoError(t, err) + require.Empty(t, res.Reads) + + _, err = f.queryServer.ReadsByTx(f.ctx, &types.QueryReadsByTxRequest{}) + require.Error(t, err) +} diff --git a/x/ucallback/keeper/settle_test.go b/x/ucallback/keeper/settle_test.go new file mode 100644 index 00000000..442b0b75 --- /dev/null +++ b/x/ucallback/keeper/settle_test.go @@ -0,0 +1,212 @@ +package keeper_test + +import ( + "math/big" + "testing" + + sdkmath "cosmossdk.io/math" + "github.com/stretchr/testify/require" + + "github.com/pushchain/push-chain-node/x/ucallback/keeper" + "github.com/pushchain/push-chain-node/x/ucallback/types" + uvalidatortypes "github.com/pushchain/push-chain-node/x/uvalidator/types" +) + +// fundedRead seeds a read with an explicit gas limit and budget. +func fundedRead(t *testing.T, f *testFixture, id string, expiry uint64, gasLimit uint64, budget string) { + t.Helper() + ur := newRead(id, "0xTX", expiry, types.UniversalReadStatus_UNIVERSAL_READ_STATUS_PENDING) + ur.Request.CallbackGasLimit = gasLimit + ur.Request.CallbackBudget = budget + require.NoError(t, f.k.SetUniversalRead(f.ctx, ur)) +} + +// ── affordability ──────────────────────────────────────────────────────────── + +// The gate is all-or-nothing: a budget short of the declared gas means no call at +// all, so the funder is refunded in full rather than charged for a doomed attempt. +func TestFulfil_UnderfundedIsNotExecuted(t *testing.T) { + f := SetupTest(t) + f.ctx = f.ctx.WithBlockHeight(10) + + // 250k gas at 1 gwei costs 2.5e14; fund one wei short of it + fundedRead(t, f, "0xaa", 500, 250_000, "249999999999999") + key := voteToQuorum(t, f, "0xaa", obs(0x01)) + + require.NoError(t, fireTerminal(f, key, uvalidatortypes.BallotStatus_BALLOT_STATUS_PASSED)) + + require.Empty(t, f.evm.calls, "the contract must not be touched") + require.True(t, f.bank.burned.IsZero(), "nothing burned") + + ur, _ := f.k.GetUniversalRead(f.ctx, "0xaa") + require.Equal(t, keeper.ErrBudgetTooSmall, ur.ErrorMsg, "the reason is on the record") + require.Equal(t, types.UniversalReadStatus_UNIVERSAL_READ_STATUS_VOTING, ur.Status, + "left in flight so the sweeper refunds the full budget") + require.Equal(t, []string{"0xaa"}, collectDueBy(t, f, 500)) +} + +// Exactly enough is enough — the boundary must not be off by one. +func TestFulfil_ExactlyAffordableExecutes(t *testing.T) { + f := SetupTest(t) + f.ctx = f.ctx.WithBlockHeight(10) + + fundedRead(t, f, "0xaa", 500, 250_000, "250000000000000") // 250k × 1 gwei + key := voteToQuorum(t, f, "0xaa", obs(0x01)) + + require.NoError(t, fireTerminal(f, key, uvalidatortypes.BallotStatus_BALLOT_STATUS_PASSED)) + + require.Equal(t, 1, f.evm.callsTo(types.MethodFulfillExternalCallback)) + ur, _ := f.k.GetUniversalRead(f.ctx, "0xaa") + require.Equal(t, types.UniversalReadStatus_UNIVERSAL_READ_STATUS_FULFILLED, ur.Status) +} + +// A zero budget is legal on the contract but funds nothing, so it never executes. +func TestFulfil_ZeroBudgetIsNotExecuted(t *testing.T) { + f := SetupTest(t) + f.ctx = f.ctx.WithBlockHeight(10) + + fundedRead(t, f, "0xaa", 500, 250_000, "0") + key := voteToQuorum(t, f, "0xaa", obs(0x01)) + + require.NoError(t, fireTerminal(f, key, uvalidatortypes.BallotStatus_BALLOT_STATUS_PASSED)) + require.Empty(t, f.evm.calls) + ur, _ := f.k.GetUniversalRead(f.ctx, "0xaa") + require.Equal(t, keeper.ErrBudgetTooSmall, ur.ErrorMsg) +} + +// ── settlement ─────────────────────────────────────────────────────────────── + +// The happy path: report what the callback cost, then destroy exactly that. +func TestSettle_ReportsThenBurns(t *testing.T) { + f := SetupTest(t) + f.ctx = f.ctx.WithBlockHeight(10) + + fundedRead(t, f, "0xaa", 500, 250_000, "1000000000000000000") + key := voteToQuorum(t, f, "0xaa", obs(0x01)) + require.NoError(t, fireTerminal(f, key, uvalidatortypes.BallotStatus_BALLOT_STATUS_PASSED)) + + // the fake receipt reports 21000 gas; at 1 gwei that is 2.1e13 + want := sdkmath.NewInt(21_000).Mul(sdkmath.NewInt(1_000_000_000)) + + report, ok := f.evm.firstCallTo(types.MethodReportCallbackGas) + require.True(t, ok, "the gas must be reported") + require.Equal(t, want.BigInt(), report.args[1], "reported cost = gasUsed × baseFee") + + require.Equal(t, want, f.bank.burned, "burn exactly what was reported") + require.Equal(t, want, f.bank.sentAmount, "and take exactly that from the contract") + require.Equal(t, types.ModuleName, f.bank.sentTo) + require.Equal(t, types.ModuleName, f.bank.burnedFrom) +} + +// The coins come out of UniversalCallback itself, not from anywhere else. +func TestSettle_TakesFromTheContract(t *testing.T) { + f := SetupTest(t) + f.ctx = f.ctx.WithBlockHeight(10) + + fundedRead(t, f, "0xaa", 500, 250_000, "1000000000000000000") + key := voteToQuorum(t, f, "0xaa", obs(0x01)) + require.NoError(t, fireTerminal(f, key, uvalidatortypes.BallotStatus_BALLOT_STATUS_PASSED)) + + require.Equal(t, contractAccAddr(), f.bank.sentFrom, + "the escrow lives on UniversalCallback, so the debit is against it") +} + +// Report before take: reportCallbackGas releases the refund and decrements +// totalEscrowed, and only then is the slack ours. Taking first would leave the +// contract briefly holding less than it owes. +func TestSettle_ReportPrecedesBurn(t *testing.T) { + f := SetupTest(t) + f.ctx = f.ctx.WithBlockHeight(10) + f.bank.sendErr = errTest // fail the take, so we can see whether the report ran + + fundedRead(t, f, "0xaa", 500, 250_000, "1000000000000000000") + key := voteToQuorum(t, f, "0xaa", obs(0x01)) + require.NoError(t, fireTerminal(f, key, uvalidatortypes.BallotStatus_BALLOT_STATUS_PASSED)) + + require.Equal(t, 1, f.evm.callsTo(types.MethodReportCallbackGas), + "the report happens before the take") + require.True(t, f.bank.burned.IsZero(), "and the burn did not") +} + +// A failed report must not burn: the contract has not released the escrow, so +// taking from it would be taking money still owed to the funder. +func TestSettle_NoBurnIfReportFails(t *testing.T) { + f := SetupTest(t) + f.ctx = f.ctx.WithBlockHeight(10) + + fundedRead(t, f, "0xaa", 500, 250_000, "1000000000000000000") + key := voteToQuorum(t, f, "0xaa", obs(0x01)) + + // the fulfil succeeds, the report reverts + f.evm.vmErrors = []string{"", "execution reverted"} + require.NoError(t, fireTerminal(f, key, uvalidatortypes.BallotStatus_BALLOT_STATUS_PASSED)) + + require.True(t, f.bank.burned.IsZero(), "nothing may be burned") + require.True(t, f.bank.sentAmount.IsZero(), "nothing may be taken") + + ur, _ := f.k.GetUniversalRead(f.ctx, "0xaa") + require.Equal(t, types.UniversalReadStatus_UNIVERSAL_READ_STATUS_FULFILLED, ur.Status, + "the callback ran, so the read is still fulfilled") + require.Contains(t, ur.ErrorMsg, "reportCallbackGas", "but the failure is visible") +} + +// Settlement failing must not undo the fulfilment — the callback really ran, and +// re-running it would revert on the contract's status guard. +func TestSettle_FailureKeepsReadTerminal(t *testing.T) { + f := SetupTest(t) + f.ctx = f.ctx.WithBlockHeight(10) + f.bank.burnErr = errTest + + fundedRead(t, f, "0xaa", 500, 250_000, "1000000000000000000") + key := voteToQuorum(t, f, "0xaa", obs(0x01)) + require.NoError(t, fireTerminal(f, key, uvalidatortypes.BallotStatus_BALLOT_STATUS_PASSED)) + + ur, _ := f.k.GetUniversalRead(f.ctx, "0xaa") + require.Equal(t, types.UniversalReadStatus_UNIVERSAL_READ_STATUS_FULFILLED, ur.Status) + require.NotEmpty(t, ur.ErrorMsg) + require.Empty(t, collectDueBy(t, f, 999), "and it does not fall back to the sweeper") +} + +// A fulfilment that never settled must not be reported or burned. +func TestSettle_SkippedWhenFulfilFails(t *testing.T) { + f := SetupTest(t) + f.ctx = f.ctx.WithBlockHeight(10) + f.evm.vmErrors = []string{"execution reverted"} + f.evm.revertData = selector("CallerIsNotUCallbackModule()") + + fundedRead(t, f, "0xaa", 500, 250_000, "1000000000000000000") + key := voteToQuorum(t, f, "0xaa", obs(0x01)) + require.NoError(t, fireTerminal(f, key, uvalidatortypes.BallotStatus_BALLOT_STATUS_PASSED)) + + require.Equal(t, 0, f.evm.callsTo(types.MethodReportCallbackGas)) + require.True(t, f.bank.burned.IsZero()) +} + +// ── pricing ────────────────────────────────────────────────────────────────── + +// The burn is clamped to the budget even if cost somehow exceeds it, so we can +// never destroy more than the funder put in. +func TestSettle_BurnNeverExceedsBudget(t *testing.T) { + f := SetupTest(t) + f.ctx = f.ctx.WithBlockHeight(10) + + // budget covers the declared limit, but the receipt reports far more gas + fundedRead(t, f, "0xaa", 500, 250_000, "250000000000000") + f.evm.gasUsed = 10_000_000 // 1e7 × 1 gwei = 1e16, far above the 2.5e14 budget + + key := voteToQuorum(t, f, "0xaa", obs(0x01)) + require.NoError(t, fireTerminal(f, key, uvalidatortypes.BallotStatus_BALLOT_STATUS_PASSED)) + + budget, _ := new(big.Int).SetString("250000000000000", 10) + require.Equal(t, budget, f.bank.burned.BigInt(), "clamped to the budget") + + report, _ := f.evm.firstCallTo(types.MethodReportCallbackGas) + require.Equal(t, budget, report.args[1], "and reported clamped, not raw") +} + +func TestCallbackCost_PricesAtBaseFee(t *testing.T) { + f := SetupTest(t) + cost, err := f.k.CallbackCost(f.ctx, 100_000) + require.NoError(t, err) + require.Equal(t, big.NewInt(100_000_000_000_000), cost, "100k gas × 1 gwei") +} diff --git a/x/ucallback/keeper/universal_read.go b/x/ucallback/keeper/universal_read.go new file mode 100644 index 00000000..6dbdf1e4 --- /dev/null +++ b/x/ucallback/keeper/universal_read.go @@ -0,0 +1,195 @@ +package keeper + +import ( + "context" + "fmt" + + "cosmossdk.io/collections" + + "github.com/pushchain/push-chain-node/x/ucallback/types" +) + +// isSettled reports whether a read has reached a terminal state and should no +// longer be swept for expiry. +func isSettled(s types.UniversalReadStatus) bool { + switch s { + case types.UniversalReadStatus_UNIVERSAL_READ_STATUS_FULFILLED, + types.UniversalReadStatus_UNIVERSAL_READ_STATUS_EXPIRED, + types.UniversalReadStatus_UNIVERSAL_READ_STATUS_FAILED, + types.UniversalReadStatus_UNIVERSAL_READ_STATUS_ABORTED: + return true + default: + return false + } +} + +// SetUniversalRead writes a read record. +// +// This is the only sanctioned way to mutate a UniversalRead. Indexes derived from +// the record are reconciled here, so writing k.UniversalReads directly will leave +// them stale — in particular the sweeper would keep expiring a read that has +// already settled. +func (k Keeper) SetUniversalRead(ctx context.Context, ur types.UniversalRead) error { + if ur.Id == "" { + return fmt.Errorf("universal read has empty request id") + } + + if err := k.UniversalReads.Set(ctx, ur.Id, ur); err != nil { + return err + } + + // pending-by-expiry: present only while unsettled + if ur.Request != nil { + key := collections.Join(ur.Request.ExpiryBlockHeight, ur.Id) + if isSettled(ur.Status) { + if err := k.PendingByExpiry.Remove(ctx, key); err != nil { + return err + } + } else if err := k.PendingByExpiry.Set(ctx, key); err != nil { + return err + } + + // aborted: present only while the read is in the abandoned state, so an + // admin retry that later succeeds takes it off the list. + if ur.Status == types.UniversalReadStatus_UNIVERSAL_READ_STATUS_ABORTED { + if err := k.AbortedReads.Set(ctx, ur.Id); err != nil { + return err + } + } else if err := k.AbortedReads.Remove(ctx, ur.Id); err != nil { + return err + } + + // reads-by-tx: written once, never removed — it is provenance, not state + if ur.Request.RequestedTxHash != "" { + if err := k.ReadsByTxHash.Set(ctx, + collections.Join(ur.Request.RequestedTxHash, ur.Id)); err != nil { + return err + } + } + } + + return nil +} + +// GetUniversalRead returns the read for requestId, if it exists. +func (k Keeper) GetUniversalRead(ctx context.Context, requestID string) (types.UniversalRead, bool) { + return k.getUniversalReadRaw(ctx, requestID) +} + +func (k Keeper) getUniversalReadRaw(ctx context.Context, requestID string) (types.UniversalRead, bool) { + ur, err := k.UniversalReads.Get(ctx, requestID) + if err != nil { + return types.UniversalRead{}, false + } + return ur, true +} + +// HasUniversalRead reports whether a read already exists. Ingest uses this to +// stay idempotent when the same log is seen twice. +func (k Keeper) HasUniversalRead(ctx context.Context, requestID string) bool { + has, err := k.UniversalReads.Has(ctx, requestID) + return err == nil && has +} + +// IterateExpiredBy calls fn for every unsettled read whose expiry height is at or +// below height, in ascending height order. The sweeper drives this. +// +// The key codec orders by expiryHeight first, so a plain ascending walk reaches +// every due entry before any that is not yet due — we break at the first key past +// height rather than constructing a cross-prefix range. +func (k Keeper) IterateExpiredBy(ctx context.Context, height uint64, fn func(types.UniversalRead) bool) error { + iter, err := k.PendingByExpiry.Iterate(ctx, nil) + if err != nil { + return err + } + defer iter.Close() + + for ; iter.Valid(); iter.Next() { + key, err := iter.Key() + if err != nil { + return err + } + if key.K1() > height { + break + } + ur, found := k.getUniversalReadRaw(ctx, key.K2()) + if !found { + continue + } + // Defence in depth. Settled reads are removed from this set by + // SetUniversalRead, so one should never appear here — but the key embeds + // ExpiryBlockHeight, and if a record were ever rewritten with a different + // deadline the old key would be orphaned and outlive the removal. The + // sweeper acting on such an entry would call expireExternalRead on an + // already-fulfilled request. + if isSettled(ur.Status) { + continue + } + if !fn(ur) { + return nil + } + } + return nil +} + +// GetUniversalReadByBallot resolves a ballot key to its read. AfterBallotTerminal +// hands us only a ballot ID, and ballot IDs are one-way digests over the +// observation — not reversible — so this scans rather than indexes. +// +// The scan is over PendingByExpiry, not UniversalReads: entries leave that set the +// moment a read settles, so it holds only in-flight work. This mirrors uexecutor's +// ballot hook, which walks PendingInbounds for the same reason +// (x/uexecutor/keeper/ballot_hooks.go:86) — the pending set is small and transient, +// and this path only runs on terminal transitions. +// +// Returns false if no pending read owns the ballot: it may have already settled by +// another path, or the ballot may not belong to this module at all. +func (k Keeper) GetUniversalReadByBallot(ctx context.Context, ballotKey string) (types.UniversalRead, bool) { + if ballotKey == "" { + return types.UniversalRead{}, false + } + + var ( + found types.UniversalRead + ok bool + ) + err := k.PendingByExpiry.Walk(ctx, nil, func(key collections.Pair[uint64, string]) (bool, error) { + ur, exists := k.getUniversalReadRaw(ctx, key.K2()) + if exists && ur.BallotKey == ballotKey { + found, ok = ur, true + return true, nil + } + return false, nil + }) + if err != nil { + return types.UniversalRead{}, false + } + return found, ok +} + +// IterateReadsByTxHash calls fn for every read requested by the given Push tx. +// A single transaction can emit several ReadRequested logs; each is its own +// record, and this is how the batch is reassembled. +func (k Keeper) IterateReadsByTxHash(ctx context.Context, txHash string, fn func(types.UniversalRead) bool) error { + rng := collections.NewPrefixedPairRange[string, string](txHash) + iter, err := k.ReadsByTxHash.Iterate(ctx, rng) + if err != nil { + return err + } + defer iter.Close() + + for ; iter.Valid(); iter.Next() { + key, err := iter.Key() + if err != nil { + return err + } + ur, found := k.getUniversalReadRaw(ctx, key.K2()) + if !found { + continue + } + if !fn(ur) { + return nil + } + } + return nil +} diff --git a/x/ucallback/keeper/universal_read_test.go b/x/ucallback/keeper/universal_read_test.go new file mode 100644 index 00000000..0a9fd923 --- /dev/null +++ b/x/ucallback/keeper/universal_read_test.go @@ -0,0 +1,264 @@ +package keeper_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/pushchain/push-chain-node/x/ucallback/types" +) + +const ( + // 250k gas at the fixture's 1 gwei base fee costs 2.5e14; the budget is far + // above it so ordinary tests never trip the affordability check. + testCallbackGasLimit = 250_000 + testCallbackBudget = "1000000000000000000" // 1 PC +) + +func newRead(id, txHash string, expiry uint64, status types.UniversalReadStatus) types.UniversalRead { + return types.UniversalRead{ + Id: id, + Status: status, + Request: &types.ReadRequest{ + RequestId: id, + DestinationChain: "eip155:1", + ExpiryBlockHeight: expiry, + RequestedTxHash: txHash, + // Funded by default: at the tests' 1 gwei base fee this covers the gas + // limit many times over, so the affordability gate is not what any test + // is exercising unless it says so. + CallbackGasLimit: testCallbackGasLimit, + CallbackBudget: testCallbackBudget, + RevertRecipient: "0x9999999999999999999999999999999999999999", + }, + } +} + +func TestSetUniversalRead_RoundTrips(t *testing.T) { + f := SetupTest(t) + + require.False(t, f.k.HasUniversalRead(f.ctx, "0xaaa")) + + ur := newRead("0xaaa", "0xTX", 100, types.UniversalReadStatus_UNIVERSAL_READ_STATUS_PENDING) + require.NoError(t, f.k.SetUniversalRead(f.ctx, ur)) + + require.True(t, f.k.HasUniversalRead(f.ctx, "0xaaa")) + got, found := f.k.GetUniversalRead(f.ctx, "0xaaa") + require.True(t, found) + require.Equal(t, "0xaaa", got.Id) + require.Equal(t, "eip155:1", got.Request.DestinationChain) + + _, found = f.k.GetUniversalRead(f.ctx, "0xmissing") + require.False(t, found) +} + +func TestSetUniversalRead_RejectsEmptyID(t *testing.T) { + f := SetupTest(t) + require.Error(t, f.k.SetUniversalRead(f.ctx, types.UniversalRead{})) +} + +func collectDueBy(t *testing.T, f *testFixture, height uint64) []string { + t.Helper() + var got []string + err := f.k.IterateExpiredBy(f.ctx, height, func(ur types.UniversalRead) bool { + got = append(got, ur.Id) + return true + }) + require.NoError(t, err) + return got +} + +// The sweep is bounded by height and ordered ascending. +func TestIterateExpiredBy_RespectsHeight(t *testing.T) { + f := SetupTest(t) + + require.NoError(t, f.k.SetUniversalRead(f.ctx, + newRead("0xlow", "0xTX", 50, types.UniversalReadStatus_UNIVERSAL_READ_STATUS_PENDING))) + require.NoError(t, f.k.SetUniversalRead(f.ctx, + newRead("0xmid", "0xTX", 100, types.UniversalReadStatus_UNIVERSAL_READ_STATUS_VOTING))) + require.NoError(t, f.k.SetUniversalRead(f.ctx, + newRead("0xhigh", "0xTX", 150, types.UniversalReadStatus_UNIVERSAL_READ_STATUS_PENDING))) + + require.Equal(t, []string{"0xlow"}, collectDueBy(t, f, 50)) + require.Equal(t, []string{"0xlow", "0xmid"}, collectDueBy(t, f, 100), "ascending by expiry height") + require.Equal(t, []string{"0xlow", "0xmid", "0xhigh"}, collectDueBy(t, f, 999)) +} + +// Settling a read removes it from the in-flight set; the record itself remains. +func TestSetUniversalRead_SettledLeavesInFlightSet(t *testing.T) { + f := SetupTest(t) + + ur := newRead("0xaaa", "0xTX", 100, types.UniversalReadStatus_UNIVERSAL_READ_STATUS_PENDING) + require.NoError(t, f.k.SetUniversalRead(f.ctx, ur)) + require.Equal(t, []string{"0xaaa"}, collectDueBy(t, f, 100)) + + ur.Status = types.UniversalReadStatus_UNIVERSAL_READ_STATUS_FULFILLED + require.NoError(t, f.k.SetUniversalRead(f.ctx, ur)) + + require.Empty(t, collectDueBy(t, f, 999), "settled reads are not swept") + require.True(t, f.k.HasUniversalRead(f.ctx, "0xaaa"), "the record survives") +} + +func collectByTx(t *testing.T, f *testFixture, txHash string) []string { + t.Helper() + var got []string + err := f.k.IterateReadsByTxHash(f.ctx, txHash, func(ur types.UniversalRead) bool { + got = append(got, ur.Id) + return true + }) + require.NoError(t, err) + return got +} + +// One Push tx emitting several ReadRequested logs produces several independent +// records that are still reassemblable as a batch. +func TestSetUniversalRead_BatchedRequestsShareTxHash(t *testing.T) { + f := SetupTest(t) + + for _, id := range []string{"0xaaa", "0xbbb", "0xccc"} { + require.NoError(t, f.k.SetUniversalRead(f.ctx, + newRead(id, "0xBATCH", 100, types.UniversalReadStatus_UNIVERSAL_READ_STATUS_PENDING))) + } + // a read from a different tx must not leak into the batch + require.NoError(t, f.k.SetUniversalRead(f.ctx, + newRead("0xddd", "0xOTHER", 100, types.UniversalReadStatus_UNIVERSAL_READ_STATUS_PENDING))) + + require.ElementsMatch(t, []string{"0xaaa", "0xbbb", "0xccc"}, collectByTx(t, f, "0xBATCH")) + require.Equal(t, []string{"0xddd"}, collectByTx(t, f, "0xOTHER")) +} + +// Siblings from one batch settle independently — one FULFILLED, one still pending. +func TestSetUniversalRead_BatchSiblingsSettleIndependently(t *testing.T) { + f := SetupTest(t) + + require.NoError(t, f.k.SetUniversalRead(f.ctx, + newRead("0xaaa", "0xBATCH", 100, types.UniversalReadStatus_UNIVERSAL_READ_STATUS_PENDING))) + require.NoError(t, f.k.SetUniversalRead(f.ctx, + newRead("0xbbb", "0xBATCH", 100, types.UniversalReadStatus_UNIVERSAL_READ_STATUS_PENDING))) + + // settle only one of them + settled := newRead("0xaaa", "0xBATCH", 100, types.UniversalReadStatus_UNIVERSAL_READ_STATUS_FULFILLED) + require.NoError(t, f.k.SetUniversalRead(f.ctx, settled)) + + // the settled one drops out of the expiry sweep, its sibling does not + require.Equal(t, []string{"0xbbb"}, collectDueBy(t, f, 100)) + // but both remain listed under the batch — reads-by-tx is provenance, not state + require.ElementsMatch(t, []string{"0xaaa", "0xbbb"}, collectByTx(t, f, "0xBATCH")) +} + +// Repointing a read's ballot key must not leave the old key resolvable. +func TestGetUniversalReadByBallot_Repointed(t *testing.T) { + f := SetupTest(t) + + ur := newRead("0xaaa", "0xTX", 100, types.UniversalReadStatus_UNIVERSAL_READ_STATUS_PENDING) + ur.BallotKey = "ballot-old" + require.NoError(t, f.k.SetUniversalRead(f.ctx, ur)) + + ur.BallotKey = "ballot-new" + require.NoError(t, f.k.SetUniversalRead(f.ctx, ur)) + + _, found := f.k.GetUniversalReadByBallot(f.ctx, "ballot-old") + require.False(t, found, "the old ballot key must no longer resolve") + + byNew, found := f.k.GetUniversalReadByBallot(f.ctx, "ballot-new") + require.True(t, found) + require.Equal(t, "0xaaa", byNew.Id) +} + +// The lookup scans the in-flight set, so a settled read is deliberately NOT +// findable by ballot. The ballot terminal hook must treat "not found" as +// "already handled", exactly as uexecutor's hook does. +func TestGetUniversalReadByBallot_SettledReadIsNotFound(t *testing.T) { + f := SetupTest(t) + + ur := newRead("0xaaa", "0xTX", 100, types.UniversalReadStatus_UNIVERSAL_READ_STATUS_PENDING) + ur.BallotKey = "ballot-1" + require.NoError(t, f.k.SetUniversalRead(f.ctx, ur)) + + _, found := f.k.GetUniversalReadByBallot(f.ctx, "ballot-1") + require.True(t, found, "resolvable while in flight") + + ur.Status = types.UniversalReadStatus_UNIVERSAL_READ_STATUS_FULFILLED + require.NoError(t, f.k.SetUniversalRead(f.ctx, ur)) + + _, found = f.k.GetUniversalReadByBallot(f.ctx, "ballot-1") + require.False(t, found, "settled reads leave the in-flight set") + + // the record itself is untouched — only the index dropped it + got, ok := f.k.GetUniversalRead(f.ctx, "0xaaa") + require.True(t, ok) + require.Equal(t, "ballot-1", got.BallotKey) +} + +// Only the read owning the ballot is returned, never a sibling sharing the scan. +func TestGetUniversalReadByBallot_PicksTheRightRead(t *testing.T) { + f := SetupTest(t) + + for i, id := range []string{"0xaaa", "0xbbb", "0xccc"} { + ur := newRead(id, "0xBATCH", uint64(100+i), + types.UniversalReadStatus_UNIVERSAL_READ_STATUS_PENDING) + ur.BallotKey = "ballot-" + id + require.NoError(t, f.k.SetUniversalRead(f.ctx, ur)) + } + + got, found := f.k.GetUniversalReadByBallot(f.ctx, "ballot-0xbbb") + require.True(t, found) + require.Equal(t, "0xbbb", got.Id) + + _, found = f.k.GetUniversalReadByBallot(f.ctx, "ballot-unknown") + require.False(t, found) +} + +// Genesis round-trips records, and rebuilds every index from them. +func TestGenesis_RoundTripRebuildsIndexes(t *testing.T) { + f := SetupTest(t) + require.NoError(t, f.k.InitGenesis(f.ctx, types.DefaultGenesis())) + + pending := newRead("0xaaa", "0xTX", 100, types.UniversalReadStatus_UNIVERSAL_READ_STATUS_PENDING) + pending.BallotKey = "ballot-1" + require.NoError(t, f.k.SetUniversalRead(f.ctx, pending)) + require.NoError(t, f.k.SetUniversalRead(f.ctx, + newRead("0xbbb", "0xTX", 100, types.UniversalReadStatus_UNIVERSAL_READ_STATUS_FULFILLED))) + + exported := f.k.ExportGenesis(f.ctx) + require.Len(t, exported.UniversalReads, 2) + + // re-import into a clean fixture + g := SetupTest(t) + require.NoError(t, g.k.InitGenesis(g.ctx, exported)) + + _, found := g.k.GetUniversalRead(g.ctx, "0xaaa") + require.True(t, found) + + // indexes are rebuilt, not imported + byBallot, found := g.k.GetUniversalReadByBallot(g.ctx, "ballot-1") + require.True(t, found) + require.Equal(t, "0xaaa", byBallot.Id) + + require.ElementsMatch(t, []string{"0xaaa", "0xbbb"}, collectByTx(t, g, "0xTX")) + require.Equal(t, []string{"0xaaa"}, collectDueBy(t, g, 100), + "only the unsettled read is pending after re-import") +} + +// The module account nonce must survive an export/import cycle. Losing it would +// make every call after a restart reuse nonces the chain already consumed. +func TestGenesis_RoundTripsModuleNonce(t *testing.T) { + f := SetupTest(t) + require.NoError(t, f.k.InitGenesis(f.ctx, types.DefaultGenesis())) + + n, err := f.k.GetModuleAccountNonce(f.ctx) + require.NoError(t, err) + require.Equal(t, uint64(0), n, "fresh genesis starts at zero") + + require.NoError(t, f.k.ModuleAccountNonce.Set(f.ctx, 42)) + + exported := f.k.ExportGenesis(f.ctx) + require.Equal(t, uint64(42), exported.ModuleAccountNonce) + + g := SetupTest(t) + require.NoError(t, g.k.InitGenesis(g.ctx, exported)) + + got, err := g.k.GetModuleAccountNonce(g.ctx) + require.NoError(t, err) + require.Equal(t, uint64(42), got) +} diff --git a/x/ucallback/keeper/uvalidator_fake_test.go b/x/ucallback/keeper/uvalidator_fake_test.go new file mode 100644 index 00000000..7653914f --- /dev/null +++ b/x/ucallback/keeper/uvalidator_fake_test.go @@ -0,0 +1,130 @@ +package keeper_test + +import ( + "context" + "fmt" + + "github.com/pushchain/push-chain-node/x/ucallback/types" + uvalidatortypes "github.com/pushchain/push-chain-node/x/uvalidator/types" +) + +// fakeUValidator is an in-memory stand-in for x/uvalidator. +// +// It tallies votes for real rather than returning a canned isFinalized, because +// the behaviour under test is precisely that two validators reporting different +// observations land on different ballots and neither reaches quorum. A stub that +// ignored the ballot key could not distinguish that from success. +type fakeUValidator struct { + voters []string + bonded map[string]bool + tombstoned map[string]bool + admin string + + ballots map[string]*fakeBallot + + // set to force an error out of the corresponding call + votersErr error + voteErr error +} + +type fakeBallot struct { + observationType uvalidatortypes.BallotObservationType + votes map[string]uvalidatortypes.VoteResult + finalized bool + expiryBlocks int64 +} + +var _ types.UValidatorKeeper = (*fakeUValidator)(nil) + +func newFakeUValidator(voters ...string) *fakeUValidator { + f := &fakeUValidator{ + voters: voters, + bonded: map[string]bool{}, + tombstoned: map[string]bool{}, + ballots: map[string]*fakeBallot{}, + } + for _, v := range voters { + f.bonded[v] = true + } + f.admin = "push1adminadminadminadminadminadminadmin" + return f +} + +func (f *fakeUValidator) GetAdmin(context.Context) (string, error) { + return f.admin, nil +} + +func (f *fakeUValidator) IsBondedUniversalValidator(_ context.Context, v string) (bool, error) { + return f.bonded[v], nil +} + +func (f *fakeUValidator) IsTombstonedUniversalValidator(_ context.Context, v string) (bool, error) { + return f.tombstoned[v], nil +} + +func (f *fakeUValidator) GetEligibleVoters(_ context.Context) ([]uvalidatortypes.UniversalValidator, error) { + if f.votersErr != nil { + return nil, f.votersErr + } + out := make([]uvalidatortypes.UniversalValidator, 0, len(f.voters)) + for _, v := range f.voters { + out = append(out, uvalidatortypes.UniversalValidator{ + IdentifyInfo: &uvalidatortypes.IdentityInfo{CoreValidatorAddress: v}, + }) + } + return out, nil +} + +func (f *fakeUValidator) VoteOnBallot( + _ context.Context, + id string, + ballotType uvalidatortypes.BallotObservationType, + voter string, + voteResult uvalidatortypes.VoteResult, + _ []string, + votesNeeded int64, + expiryAfterBlocks int64, +) (uvalidatortypes.Ballot, bool, bool, error) { + if f.voteErr != nil { + return uvalidatortypes.Ballot{}, false, false, f.voteErr + } + + b, existed := f.ballots[id] + if !existed { + b = &fakeBallot{ + observationType: ballotType, + votes: map[string]uvalidatortypes.VoteResult{}, + expiryBlocks: expiryAfterBlocks, + } + f.ballots[id] = b + } + + if b.finalized { + return uvalidatortypes.Ballot{Id: id}, true, false, nil + } + if _, dup := b.votes[voter]; dup { + return uvalidatortypes.Ballot{Id: id}, false, false, + fmt.Errorf("validator %s already voted on ballot %s", voter, id) + } + + b.votes[voter] = voteResult + b.finalized = int64(len(b.votes)) >= votesNeeded + + return uvalidatortypes.Ballot{Id: id}, b.finalized, !existed, nil +} + +// ballotCount reports how many distinct ballots have been opened — the signal that +// validators diverged on what they observed. +func (f *fakeUValidator) ballotCount() int { return len(f.ballots) } + +// expiryOf returns the relative expiry a ballot was created with. +func (f *fakeUValidator) expiryOf(id string) int64 { + b, ok := f.ballots[id] + if !ok { + return -1 + } + return b.expiryBlocks +} + +// errTest is a sentinel for injecting failures into the fake. +var errTest = fmt.Errorf("injected test failure") diff --git a/x/ucallback/keeper/voting.go b/x/ucallback/keeper/voting.go new file mode 100644 index 00000000..15280484 --- /dev/null +++ b/x/ucallback/keeper/voting.go @@ -0,0 +1,191 @@ +package keeper + +import ( + "context" + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/pushchain/push-chain-node/x/ucallback/types" + uvalidatortypes "github.com/pushchain/push-chain-node/x/uvalidator/types" +) + +// VoteOnReadBallot casts one validator's vote on the ballot for (requestID, result) +// and reports whether that vote carried it to quorum. +// +// Mirrors x/uexecutor's VoteOnOutboundBallot for the threshold and voter set, but +// not for expiry: the ballot is given the request's own deadline rather than +// uexecutor's inert 100M blocks, so the two cannot disagree about when the request +// is over. +func (k Keeper) VoteOnReadBallot( + ctx context.Context, + universalValidator sdk.ValAddress, + requestID string, + result *types.ReadResult, + expiryHeight uint64, +) (ballotKey string, isFinalized bool, isNew bool, err error) { + ballotKey, err = types.GetReadBallotKey(requestID, result) + if err != nil { + return "", false, false, err + } + + voters, err := k.uvalidatorKeeper.GetEligibleVoters(ctx) + if err != nil { + return "", false, false, err + } + if len(voters) == 0 { + return "", false, false, fmt.Errorf("no eligible universal validators") + } + + // votesNeeded = floor(2/3 * n) + 1, i.e. a strict >2/3 majority, matching + // tendermint and every other ballot on this chain. + votesNeeded := (types.VotesThresholdNumerator*len(voters))/types.VotesThresholdDenominator + 1 + + voterAddrs := make([]string, len(voters)) + for i, v := range voters { + voterAddrs[i] = v.IdentifyInfo.CoreValidatorAddress + } + + expiryAfterBlocks := types.BallotExpiryAfterBlocks( + expiryHeight, sdk.UnwrapSDKContext(ctx).BlockHeight()) + + k.Logger().Debug("voting on read ballot", + "ballot_key", ballotKey, + "request_id", requestID, + "validator", universalValidator.String(), + "total_validators", len(voters), + "votes_needed", votesNeeded, + "expiry_height", expiryHeight, + "expiry_after_blocks", expiryAfterBlocks, + ) + + _, isFinalized, isNew, err = k.uvalidatorKeeper.VoteOnBallot( + ctx, + ballotKey, + uvalidatortypes.BallotObservationType_BALLOT_OBSERVATION_TYPE_READ_RESULT, + universalValidator.String(), + // Always SUCCESS: disagreement is expressed by landing on a different + // ballot key, not by voting FAILURE on a shared one. A FAILURE vote here + // would mean "this exact observation is wrong", which no validator is in a + // position to assert — it only knows what it observed itself. + uvalidatortypes.VoteResult_VOTE_RESULT_SUCCESS, + voterAddrs, + int64(votesNeeded), + expiryAfterBlocks, + ) + if err != nil { + return "", false, false, err + } + + if isNew { + k.Logger().Debug("read ballot created", "ballot_key", ballotKey, "request_id", requestID) + } + if isFinalized { + k.Logger().Info("read ballot finalized", "ballot_key", ballotKey, "request_id", requestID) + } + + return ballotKey, isFinalized, isNew, nil +} + +// VoteReadResult records a universal validator's observation of a read request. +// +// Reaching quorum here does NOT fulfil the request — it only settles what was +// observed. The fulfilment EVM call is driven by the ballot terminal hook (C7), so +// that it runs exactly once no matter which validator's vote happened to be the +// deciding one. +func (k Keeper) VoteReadResult( + ctx context.Context, + universalValidator sdk.ValAddress, + requestID string, + result *types.ReadResult, +) (bool, error) { + if err := types.ValidateReadResult(result); err != nil { + return false, err + } + + ur, found := k.GetUniversalRead(ctx, requestID) + if !found { + return false, fmt.Errorf("read request not found: %s", requestID) + } + + // Only unsettled requests accept votes. Without this a validator could keep + // voting on a request that already fulfilled, creating ballots that the + // terminal hook would then try to act on a second time. + if isSettled(ur.Status) { + return false, fmt.Errorf("read request %s is already %s", requestID, ur.Status) + } + + if ur.Request == nil { + return false, fmt.Errorf("read request %s has no request body", requestID) + } + + // Reject votes on a request whose deadline has passed. AllPendingReadRequests + // already withholds these, so an honest validator will not be voting on one — + // but the query is a convenience, not the enforcement point. + sdkCtx := sdk.UnwrapSDKContext(ctx) + if ur.Request.ExpiryBlockHeight <= uint64(sdkCtx.BlockHeight()) { + return false, fmt.Errorf("read request %s expired at height %d", + requestID, ur.Request.ExpiryBlockHeight) + } + + // Cache the vote so a failure partway through leaves no half-written ballot. + tmpCtx, commit := sdkCtx.CacheContext() + + ballotKey, err := types.GetReadBallotKey(requestID, result) + if err != nil { + return false, err + } + + // The record must carry this ballot key and observation BEFORE the vote is + // cast, not after. + // + // VoteOnBallot fires the terminal hook synchronously the moment this vote + // reaches quorum, and that hook finds the request BY ballot key and needs + // ur.Result to fulfil it. Writing them afterwards left the deciding vote + // looking at a record still pointing at whatever observation was voted + // previously — so the hook missed, and a read that had genuinely reached + // quorum sat in VOTING until the sweeper expired and refunded it. It also put + // this write after the hook's, clobbering FULFILLED back to VOTING. + // + // Until a ballot finalizes these two fields track whichever observation this + // validator's vote most recently landed on; quorum is what makes them binding. + ur.Status = types.UniversalReadStatus_UNIVERSAL_READ_STATUS_VOTING + ur.BallotKey = ballotKey + ur.Result = result + if err := k.SetUniversalRead(tmpCtx, ur); err != nil { + return false, err + } + + _, isFinalized, _, err := k.VoteOnReadBallot( + tmpCtx, universalValidator, requestID, result, ur.Request.ExpiryBlockHeight) + if err != nil { + return false, err + } + + if !isFinalized { + // The observation was staged above only so the terminal hook could reach it. + // No ballot passed, so nothing is settled and the record must not imply a + // consensus that does not exist — a stored Result means quorum. + // + // Re-read rather than reusing `ur`: the vote may have driven some OTHER + // ballot terminal, and writing our stale copy back would undo that. + cur, found := k.GetUniversalRead(tmpCtx, requestID) + if found && !isSettled(cur.Status) { + cur.Result = nil + if err := k.SetUniversalRead(tmpCtx, cur); err != nil { + return false, err + } + } + } + + commit() + + k.Logger().Info("read result vote recorded", + "request_id", requestID, + "validator", universalValidator.String(), + "ballot_key", ballotKey, + "finalized", isFinalized, + ) + + return isFinalized, nil +} diff --git a/x/ucallback/keeper/voting_test.go b/x/ucallback/keeper/voting_test.go new file mode 100644 index 00000000..6949396b --- /dev/null +++ b/x/ucallback/keeper/voting_test.go @@ -0,0 +1,361 @@ +package keeper_test + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" + + "github.com/pushchain/push-chain-node/x/ucallback/types" +) + +func obs(data byte) *types.ReadResult { + return &types.ReadResult{ + Status: types.ReadStatus_READ_STATUS_SUCCESS, + ResultData: []byte{data}, + } +} + +// seedVoters configures n eligible validators and returns their val addresses. +func seedVoters(t *testing.T, f *testFixture, n int) []sdk.ValAddress { + t.Helper() + addrs := make([]sdk.ValAddress, n) + names := make([]string, n) + for i := 0; i < n; i++ { + addrs[i] = sdk.ValAddress(f.addrs[i%len(f.addrs)]) + // keep them distinct even when recycling the base accounts + names[i] = addrs[i].String() + string(rune('a'+i)) + addrs[i] = sdk.ValAddress(names[i]) + } + f.uvalidator.voters = names + for _, nm := range names { + f.uvalidator.bonded[nm] = true + } + return addrs +} + +func seedRead(t *testing.T, f *testFixture, id string, expiry uint64) { + t.Helper() + require.NoError(t, f.k.SetUniversalRead(f.ctx, + newRead(id, "0xTX", expiry, types.UniversalReadStatus_UNIVERSAL_READ_STATUS_PENDING))) +} + +// A single vote below quorum moves the request to VOTING and attaches a ballot, +// but does not settle it. +func TestVoteReadResult_FirstVoteDoesNotFinalize(t *testing.T) { + f := SetupTest(t) + f.ctx = f.ctx.WithBlockHeight(10) + v := seedVoters(t, f, 4) + seedRead(t, f, "0xaa", 500) + + finalized, err := f.k.VoteReadResult(f.ctx, v[0], "0xaa", obs(0x01)) + require.NoError(t, err) + require.False(t, finalized, "1 of 4 is below the >2/3 threshold") + + ur, found := f.k.GetUniversalRead(f.ctx, "0xaa") + require.True(t, found) + require.Equal(t, types.UniversalReadStatus_UNIVERSAL_READ_STATUS_VOTING, ur.Status) + require.NotEmpty(t, ur.BallotKey) + require.Nil(t, ur.Result, "result is only attached once the ballot finalizes") + + // still offered to validators — the rest have not voted yet + require.Equal(t, []string{"0xaa"}, pendingIDs(t, f)) +} + +// Agreement on the same observation reaches quorum at floor(2/3n)+1. +func TestVoteReadResult_QuorumFinalizes(t *testing.T) { + f := SetupTest(t) + f.ctx = f.ctx.WithBlockHeight(10) + v := seedVoters(t, f, 4) // votesNeeded = (2*4)/3 + 1 = 3 + seedRead(t, f, "0xaa", 500) + + for i := 0; i < 2; i++ { + finalized, err := f.k.VoteReadResult(f.ctx, v[i], "0xaa", obs(0x01)) + require.NoError(t, err) + require.False(t, finalized, "vote %d must not finalize", i+1) + } + + finalized, err := f.k.VoteReadResult(f.ctx, v[2], "0xaa", obs(0x01)) + require.NoError(t, err) + require.True(t, finalized, "third of four carries the ballot") + + ur, found := f.k.GetUniversalRead(f.ctx, "0xaa") + require.True(t, found) + require.NotNil(t, ur.Result, "the winning observation is attached") + require.Equal(t, []byte{0x01}, ur.Result.ResultData) + + require.Equal(t, 1, f.uvalidator.ballotCount(), "agreement means one ballot") +} + +// Divergent observations open separate ballots and neither reaches quorum. This is +// the core property of the design: agreement is expressed by arriving at the same +// key, so disagreement simply fails to accumulate. +func TestVoteReadResult_DivergentObservationsSplitBallots(t *testing.T) { + f := SetupTest(t) + f.ctx = f.ctx.WithBlockHeight(10) + v := seedVoters(t, f, 4) + seedRead(t, f, "0xaa", 500) + + for i, data := range []byte{0x01, 0x02, 0x03} { + finalized, err := f.k.VoteReadResult(f.ctx, v[i], "0xaa", obs(data)) + require.NoError(t, err) + require.False(t, finalized, "observation %d must not finalize alone", i) + } + + require.Equal(t, 3, f.uvalidator.ballotCount(), + "three distinct observations must produce three ballots") + + ur, _ := f.k.GetUniversalRead(f.ctx, "0xaa") + require.Nil(t, ur.Result, "no observation won, so none is recorded") + require.Equal(t, types.UniversalReadStatus_UNIVERSAL_READ_STATUS_VOTING, ur.Status) +} + +// A minority that diverges cannot stop the majority from finalizing. +func TestVoteReadResult_MinorityDivergenceDoesNotBlock(t *testing.T) { + f := SetupTest(t) + f.ctx = f.ctx.WithBlockHeight(10) + v := seedVoters(t, f, 4) + seedRead(t, f, "0xaa", 500) + + _, err := f.k.VoteReadResult(f.ctx, v[0], "0xaa", obs(0xff)) // the outlier + require.NoError(t, err) + + for i := 1; i <= 2; i++ { + _, err := f.k.VoteReadResult(f.ctx, v[i], "0xaa", obs(0x01)) + require.NoError(t, err) + } + finalized, err := f.k.VoteReadResult(f.ctx, v[3], "0xaa", obs(0x01)) + require.NoError(t, err) + require.True(t, finalized) + + ur, _ := f.k.GetUniversalRead(f.ctx, "0xaa") + require.Equal(t, []byte{0x01}, ur.Result.ResultData, "the majority observation wins") +} + +func TestVoteReadResult_RejectsUnknownRequest(t *testing.T) { + f := SetupTest(t) + v := seedVoters(t, f, 4) + + _, err := f.k.VoteReadResult(f.ctx, v[0], "0xmissing", obs(0x01)) + require.ErrorContains(t, err, "not found") +} + +// Once settled, further votes must be refused — otherwise the terminal hook could +// be driven a second time. +func TestVoteReadResult_RejectsSettled(t *testing.T) { + f := SetupTest(t) + f.ctx = f.ctx.WithBlockHeight(10) + v := seedVoters(t, f, 4) + + for _, st := range []types.UniversalReadStatus{ + types.UniversalReadStatus_UNIVERSAL_READ_STATUS_FULFILLED, + types.UniversalReadStatus_UNIVERSAL_READ_STATUS_EXPIRED, + types.UniversalReadStatus_UNIVERSAL_READ_STATUS_FAILED, + } { + id := "0x" + st.String() + require.NoError(t, f.k.SetUniversalRead(f.ctx, newRead(id, "0xTX", 500, st))) + _, err := f.k.VoteReadResult(f.ctx, v[0], id, obs(0x01)) + require.ErrorContains(t, err, "already", "status %s must reject votes", st) + } +} + +// Past its deadline a request stops accepting votes, independently of whether the +// sweeper has retired it yet. +func TestVoteReadResult_RejectsExpired(t *testing.T) { + f := SetupTest(t) + f.ctx = f.ctx.WithBlockHeight(100) + v := seedVoters(t, f, 4) + + seedRead(t, f, "0xpast", 50) + _, err := f.k.VoteReadResult(f.ctx, v[0], "0xpast", obs(0x01)) + require.ErrorContains(t, err, "expired") + + // exactly at the expiry height is already too late, matching the query filter + seedRead(t, f, "0xnow", 100) + _, err = f.k.VoteReadResult(f.ctx, v[0], "0xnow", obs(0x01)) + require.ErrorContains(t, err, "expired") + + seedRead(t, f, "0xlive", 101) + _, err = f.k.VoteReadResult(f.ctx, v[0], "0xlive", obs(0x01)) + require.NoError(t, err) +} + +func TestVoteReadResult_RejectsNilResult(t *testing.T) { + f := SetupTest(t) + v := seedVoters(t, f, 4) + seedRead(t, f, "0xaa", 500) + + _, err := f.k.VoteReadResult(f.ctx, v[0], "0xaa", nil) + require.Error(t, err) +} + +// A failure inside voting must leave no trace — the request stays exactly as it was. +func TestVoteReadResult_FailureIsAtomic(t *testing.T) { + f := SetupTest(t) + f.ctx = f.ctx.WithBlockHeight(10) + v := seedVoters(t, f, 4) + seedRead(t, f, "0xaa", 500) + + f.uvalidator.voteErr = errTest + _, err := f.k.VoteReadResult(f.ctx, v[0], "0xaa", obs(0x01)) + require.Error(t, err) + + ur, found := f.k.GetUniversalRead(f.ctx, "0xaa") + require.True(t, found) + require.Equal(t, types.UniversalReadStatus_UNIVERSAL_READ_STATUS_PENDING, ur.Status, + "a failed vote must not advance the request") + require.Empty(t, ur.BallotKey) +} + +func TestVoteReadResult_RejectsWhenNoVoters(t *testing.T) { + f := SetupTest(t) + f.ctx = f.ctx.WithBlockHeight(10) + seedRead(t, f, "0xaa", 500) + + _, err := f.k.VoteReadResult(f.ctx, sdk.ValAddress("nobody"), "0xaa", obs(0x01)) + require.ErrorContains(t, err, "no eligible") +} + +// The ballot the record points at is the one the terminal hook will resolve back. +func TestVoteReadResult_BallotResolvesBackToRequest(t *testing.T) { + f := SetupTest(t) + f.ctx = f.ctx.WithBlockHeight(10) + v := seedVoters(t, f, 4) + seedRead(t, f, "0xaa", 500) + + _, err := f.k.VoteReadResult(f.ctx, v[0], "0xaa", obs(0x01)) + require.NoError(t, err) + + ur, _ := f.k.GetUniversalRead(f.ctx, "0xaa") + back, found := f.k.GetUniversalReadByBallot(f.ctx, ur.BallotKey) + require.True(t, found, "the terminal hook must be able to find this request") + require.Equal(t, "0xaa", back.Id) +} + +// The ballot's deadline must be the request's own. x/uvalidator stores expiry as +// created + delta, so the delta handed to VoteOnBallot has to close exactly that +// gap — otherwise the two clocks disagree about when the request is over. +func TestVoteReadResult_BallotInheritsRequestDeadline(t *testing.T) { + f := SetupTest(t) + f.ctx = f.ctx.WithBlockHeight(120) + v := seedVoters(t, f, 4) + seedRead(t, f, "0xaa", 500) + + _, err := f.k.VoteReadResult(f.ctx, v[0], "0xaa", obs(0x01)) + require.NoError(t, err) + + ur, _ := f.k.GetUniversalRead(f.ctx, "0xaa") + delta := f.uvalidator.expiryOf(ur.BallotKey) + require.Equal(t, int64(380), delta, "500 - 120") + require.Equal(t, int64(500), f.ctx.BlockHeight()+delta, + "ballot expires exactly when the request does") +} + +// Requests with different deadlines must not share one expiry. +func TestVoteReadResult_DeadlineIsPerRequest(t *testing.T) { + f := SetupTest(t) + f.ctx = f.ctx.WithBlockHeight(100) + v := seedVoters(t, f, 4) + + seedRead(t, f, "0xsoon", 150) + seedRead(t, f, "0xlate", 9_000) + + _, err := f.k.VoteReadResult(f.ctx, v[0], "0xsoon", obs(0x01)) + require.NoError(t, err) + _, err = f.k.VoteReadResult(f.ctx, v[0], "0xlate", obs(0x01)) + require.NoError(t, err) + + soon, _ := f.k.GetUniversalRead(f.ctx, "0xsoon") + late, _ := f.k.GetUniversalRead(f.ctx, "0xlate") + + require.Equal(t, int64(50), f.uvalidator.expiryOf(soon.BallotKey)) + require.Equal(t, int64(8_900), f.uvalidator.expiryOf(late.BallotKey)) +} + +func TestVoteReadResult_RejectsMissingRequestBody(t *testing.T) { + f := SetupTest(t) + f.ctx = f.ctx.WithBlockHeight(10) + v := seedVoters(t, f, 4) + + require.NoError(t, f.k.SetUniversalRead(f.ctx, types.UniversalRead{ + Id: "0xnobody", + Status: types.UniversalReadStatus_UNIVERSAL_READ_STATUS_PENDING, + })) + + _, err := f.k.VoteReadResult(f.ctx, v[0], "0xnobody", obs(0x01)) + require.ErrorContains(t, err, "no request body") +} + +// Validators that agree the read failed but disagree on why must not finalize. +func TestVoteReadResult_ErrorCodesSplitBallots(t *testing.T) { + f := SetupTest(t) + f.ctx = f.ctx.WithBlockHeight(10) + v := seedVoters(t, f, 4) + seedRead(t, f, "0xaa", 500) + + errVote := func(code types.ReadErrorCode) *types.ReadResult { + return &types.ReadResult{Status: types.ReadStatus_READ_STATUS_ERROR, ErrorCode: code} + } + + for i, code := range []types.ReadErrorCode{ + types.ReadErrorCode_READ_ERROR_REVERTED, + types.ReadErrorCode_READ_ERROR_NOT_FOUND, + types.ReadErrorCode_READ_ERROR_INVALID_QUERY, + } { + finalized, err := f.k.VoteReadResult(f.ctx, v[i], "0xaa", errVote(code)) + require.NoError(t, err) + require.False(t, finalized, "%s must not finalize alone", code) + } + require.Equal(t, 3, f.uvalidator.ballotCount(), "one ballot per reason") +} + +// Agreeing on the reason reaches quorum, and the code is recorded. +func TestVoteReadResult_AgreedErrorFinalizes(t *testing.T) { + f := SetupTest(t) + f.ctx = f.ctx.WithBlockHeight(10) + v := seedVoters(t, f, 4) + seedRead(t, f, "0xaa", 500) + + same := func() *types.ReadResult { + return &types.ReadResult{ + Status: types.ReadStatus_READ_STATUS_ERROR, + ErrorCode: types.ReadErrorCode_READ_ERROR_NOT_FOUND, + } + } + for i := 0; i < 2; i++ { + _, err := f.k.VoteReadResult(f.ctx, v[i], "0xaa", same()) + require.NoError(t, err) + } + finalized, err := f.k.VoteReadResult(f.ctx, v[2], "0xaa", same()) + require.NoError(t, err) + require.True(t, finalized) + + ur, _ := f.k.GetUniversalRead(f.ctx, "0xaa") + require.Equal(t, types.ReadStatus_READ_STATUS_ERROR, ur.Result.Status) + require.Equal(t, types.ReadErrorCode_READ_ERROR_NOT_FOUND, ur.Result.ErrorCode) + require.Equal(t, 1, f.uvalidator.ballotCount()) +} + +// Malformed observations are refused before they can open a lonely ballot. +func TestVoteReadResult_RejectsInvalidObservations(t *testing.T) { + f := SetupTest(t) + f.ctx = f.ctx.WithBlockHeight(10) + v := seedVoters(t, f, 4) + seedRead(t, f, "0xaa", 500) + + for name, bad := range map[string]*types.ReadResult{ + "nil": nil, + "success with error code": { + Status: types.ReadStatus_READ_STATUS_SUCCESS, + ErrorCode: types.ReadErrorCode_READ_ERROR_REVERTED}, + "error with data": { + Status: types.ReadStatus_READ_STATUS_ERROR, ResultData: []byte{1}}, + } { + t.Run(name, func(t *testing.T) { + _, err := f.k.VoteReadResult(f.ctx, v[0], "0xaa", bad) + require.Error(t, err) + }) + } + + require.Equal(t, 0, f.uvalidator.ballotCount(), "no ballot opened by a rejected vote") +} diff --git a/x/ucallback/module.go b/x/ucallback/module.go new file mode 100755 index 00000000..2c598f77 --- /dev/null +++ b/x/ucallback/module.go @@ -0,0 +1,171 @@ +package module + +import ( + "context" + + "cosmossdk.io/core/appmodule" + "encoding/json" + + "github.com/gorilla/mux" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + + abci "github.com/cometbft/cometbft/abci/types" + + "cosmossdk.io/client/v2/autocli" + errorsmod "cosmossdk.io/errors" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/codec" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + + "github.com/pushchain/push-chain-node/x/ucallback/keeper" + "github.com/pushchain/push-chain-node/x/ucallback/types" +) + +const ( + // ConsensusVersion defines the current x/ucallback module consensus version. + ConsensusVersion = 1 +) + +var ( + _ module.AppModuleBasic = AppModuleBasic{} + _ module.AppModuleGenesis = AppModule{} + _ module.AppModule = AppModule{} + + // Compile-time proof that EndBlock is the shape the module manager looks for. + // The manager finds it by runtime type assertion, so without this a signature + // typo would compile fine and the sweeper would simply never run. + _ appmodule.HasEndBlocker = AppModule{} + + _ autocli.HasAutoCLIConfig = AppModule{} +) + +// AppModuleBasic defines the basic application module used by the wasm module. +type AppModuleBasic struct { + cdc codec.Codec +} + +type AppModule struct { + AppModuleBasic + + keeper keeper.Keeper +} + +// NewAppModule constructor +func NewAppModule( + cdc codec.Codec, + keeper keeper.Keeper, +) *AppModule { + return &AppModule{ + AppModuleBasic: AppModuleBasic{cdc: cdc}, + keeper: keeper, + } +} + +func (a AppModuleBasic) Name() string { + return types.ModuleName +} + +func (a AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { + return cdc.MustMarshalJSON(&types.GenesisState{ + Params: types.DefaultParams(), + }) +} + +func (a AppModuleBasic) ValidateGenesis(marshaler codec.JSONCodec, _ client.TxEncodingConfig, message json.RawMessage) error { + var data types.GenesisState + err := marshaler.UnmarshalJSON(message, &data) + if err != nil { + return err + } + if err := data.Params.Validate(); err != nil { + return errorsmod.Wrap(err, "params") + } + return nil +} + +func (a AppModuleBasic) RegisterRESTRoutes(_ client.Context, _ *mux.Router) { +} + +func (a AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) { + err := types.RegisterQueryHandlerClient(context.Background(), mux, types.NewQueryClient(clientCtx)) + if err != nil { + // same behavior as in cosmos-sdk + panic(err) + } +} + +// Disable in favor of autocli.go. If you wish to use these, it will override AutoCLI methods. +/* +func (a AppModuleBasic) GetTxCmd() *cobra.Command { + return cli.NewTxCmd() +} + +func (a AppModuleBasic) GetQueryCmd() *cobra.Command { + return cli.GetQueryCmd() +} +*/ + +func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { + types.RegisterLegacyAminoCodec(cdc) +} + +func (a AppModuleBasic) RegisterInterfaces(r codectypes.InterfaceRegistry) { + types.RegisterInterfaces(r) +} + +func (a AppModule) InitGenesis(ctx sdk.Context, marshaler codec.JSONCodec, message json.RawMessage) []abci.ValidatorUpdate { + var genesisState types.GenesisState + marshaler.MustUnmarshalJSON(message, &genesisState) + + if err := a.keeper.Params.Set(ctx, genesisState.Params); err != nil { + panic(err) + } + + if err := a.keeper.InitGenesis(ctx, &genesisState); err != nil { + panic(err) + } + + return nil +} + +func (a AppModule) ExportGenesis(ctx sdk.Context, marshaler codec.JSONCodec) json.RawMessage { + genState := a.keeper.ExportGenesis(ctx) + return marshaler.MustMarshalJSON(genState) +} + +func (a AppModule) RegisterInvariants(_ sdk.InvariantRegistry) { +} + +func (a AppModule) QuerierRoute() string { + return types.QuerierRoute +} + +func (a AppModule) RegisterServices(cfg module.Configurator) { + types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(a.keeper)) + types.RegisterQueryServer(cfg.QueryServer(), keeper.NewQuerier(a.keeper)) +} + +// ConsensusVersion is a sequence number for state-breaking change of the +// module. It should be incremented on each consensus-breaking change +// introduced by the module. To avoid wrong/empty versions, the initial version +// should be set to 1. +// EndBlock retires read requests whose deadline has passed. +// +// Errors are logged rather than returned: a failure to sweep is not worth halting +// the chain over, and the work is idempotent — anything missed is still in +// PendingByExpiry and gets picked up next block. +func (a AppModule) EndBlock(ctx context.Context) error { + sdkCtx := sdk.UnwrapSDKContext(ctx) + if err := a.keeper.SweepExpired(sdkCtx); err != nil { + sdkCtx.Logger().Error("ucallback: expiry sweep failed", + "height", sdkCtx.BlockHeight(), "err", err.Error()) + } + return nil +} + +func (a AppModule) ConsensusVersion() uint64 { + return ConsensusVersion +} diff --git a/x/ucallback/types/ballot.go b/x/ucallback/types/ballot.go new file mode 100644 index 00000000..6b4096c0 --- /dev/null +++ b/x/ucallback/types/ballot.go @@ -0,0 +1,154 @@ +package types + +import ( + "crypto/sha256" + "encoding/hex" + "fmt" + "strings" + + "cosmossdk.io/collections" +) + +// ReadBallotDomain separates read-result ballot keys from every other ballot +// namespace on the chain, so a digest collision across modules is not possible. +var ReadBallotDomain = collections.NewPrefix(1) + +// VotesThresholdNumerator / VotesThresholdDenominator give the >2/3 quorum used +// chain-wide. Mirrors x/uexecutor's constants so read ballots finalize on the same +// threshold as inbound and outbound ones. +const ( + VotesThresholdNumerator = 2 + VotesThresholdDenominator = 3 +) + +// BallotExpiryAfterBlocks converts a read request's absolute deadline into the +// relative argument VoteOnBallot expects. +// +// x/uvalidator stores BlockHeightExpiry as createdHeight + expiryAfterBlocks +// (types/ballot.go:109), so an absolute target has to be expressed as a delta from +// the height the ballot is created at. +// +// The two clocks are deliberately fused: the ballot expires exactly when the +// request does. x/uexecutor instead passes an inert 100M-block expiry to keep +// ballots alive indefinitely, but a read has a real deadline of its own — set by +// the app, enforced by the contract at UniversalCallback.sol:207 — and a ballot +// that outlived it could only ever finalize into a request no longer worth +// fulfilling. +// +// Returns at least 1 so a ballot is never created already expired. Callers reject +// past-deadline requests before reaching here; this is the backstop. +func BallotExpiryAfterBlocks(expiryHeight uint64, currentHeight int64) int64 { + delta := int64(expiryHeight) - currentHeight + if delta < 1 { + return 1 + } + return delta +} + +// GetReadBallotKey derives the ballot a (requestId, observation) pair votes on. +// +// The ballot model is binary: validators vote SUCCESS or FAILURE on a key that +// already encodes the observation. Agreement is therefore expressed by arriving at +// the same key — two validators reporting different result data produce different +// ballots, and neither reaches quorum until enough validators agree. +// +// Two consequences follow, and both are load-bearing: +// +// 1. Every field that callers must agree on has to be in this digest. Omitting one +// would let validators finalize a ballot while disagreeing about it. +// +// 2. Nothing validator-local may be in it. This is why ReadResult carries no error +// message: free-text error strings differ per validator, so including one would +// scatter honest validators across distinct ballots and quorum would never form. +// x/uexecutor's outbound key does hash an ErrorMsg (keys.go:158) — we deliberately +// do not follow it there. +// +// Aggregates are excluded, see readResultFields. +func GetReadBallotKey(requestID string, result *ReadResult) (string, error) { + if requestID == "" { + return "", fmt.Errorf("cannot derive ballot key: empty request id") + } + if result == nil { + return "", fmt.Errorf("cannot derive ballot key: nil result") + } + + parts := append([]string{strings.ToLower(requestID)}, readResultFields(result)...) + return hashFields(ReadBallotDomain, parts...), nil +} + +// readResultFields renders the consensus-relevant part of an observation. +// +// error_code is included: disagreement about WHY a read failed is real +// disagreement. One validator reporting REVERTED and another NOT_FOUND saw +// different things, and splitting the ballot is the correct outcome — letting both +// collapse onto a bare ERROR would paper over it. +// +// `aggregates` is deliberately absent. It is reserved for v2 MEDIAN mode, where +// validators submit differing per-field values that are reduced afterwards — the +// opposite of the identical-observation model this key assumes. Hashing it now +// would be harmless (it is always empty in v1) but would silently become +// consensus-breaking the moment v2 populates it: the same read would map to a +// different ballot before and after the upgrade. Excluding it from the start keeps +// v2 a purely additive change. +func readResultFields(r *ReadResult) []string { + return []string{ + fmt.Sprintf("%d", int32(r.Status)), + fmt.Sprintf("%d", int32(r.ErrorCode)), + hex.EncodeToString(r.ResultData), + } +} + +// hashFields builds a domain-separated digest over pre-hashed parts, so a value +// containing the ":" join character cannot be made to impersonate a field boundary. +// Same construction as x/uexecutor/types/keys.go:83. +func hashFields(domain collections.Prefix, parts ...string) string { + hashed := make([]string, 0, len(parts)+1) + d := sha256.Sum256(domain.Bytes()) + hashed = append(hashed, hex.EncodeToString(d[:])) + for _, p := range parts { + sum := sha256.Sum256([]byte(p)) + hashed = append(hashed, hex.EncodeToString(sum[:])) + } + final := sha256.Sum256([]byte(strings.Join(hashed, ":"))) + return hex.EncodeToString(final[:]) +} + +// ValidateReadResult rejects observations that cannot be honest, before they reach +// a ballot. +// +// These are not defensive niceties: each rejected shape would produce a ballot key +// that no other validator observing the same thing could reach, so an accepted one +// would sit alone and never reach quorum. Failing loudly at submission turns a +// silent stall into an error the operator can see. +func ValidateReadResult(r *ReadResult) error { + if r == nil { + return fmt.Errorf("read result is required") + } + + switch r.Status { + case ReadStatus_READ_STATUS_SUCCESS: + if r.ErrorCode != ReadErrorCode_READ_ERROR_UNSPECIFIED { + return fmt.Errorf("successful read must not carry error code %s", r.ErrorCode) + } + + case ReadStatus_READ_STATUS_ERROR: + // result_data must be empty. A failed read has no payload to deliver, and + // error detail differs per provider — one validator attaching a revert + // blob and another attaching nothing would split the ballot. + if len(r.ResultData) != 0 { + return fmt.Errorf("failed read must not carry result data (%d bytes)", len(r.ResultData)) + } + + default: + return fmt.Errorf("read status %s is not a valid observation", r.Status) + } + + // Reserved for v2 MEDIAN; a v1 validator populating it is running code this + // chain cannot interpret, and it is excluded from the ballot key so the + // divergence would be invisible. + if len(r.Aggregates) != 0 { + return fmt.Errorf("aggregates are not supported in v1") + } + + return nil +} diff --git a/x/ucallback/types/ballot_test.go b/x/ucallback/types/ballot_test.go new file mode 100644 index 00000000..ed00edb2 --- /dev/null +++ b/x/ucallback/types/ballot_test.go @@ -0,0 +1,327 @@ +package types_test + +import ( + "errors" + "testing" + + "github.com/ethereum/go-ethereum/crypto" + "github.com/stretchr/testify/require" + + "github.com/pushchain/push-chain-node/x/ucallback/types" +) + +func result() *types.ReadResult { + return &types.ReadResult{ + Status: types.ReadStatus_READ_STATUS_SUCCESS, + ResultData: []byte{0xde, 0xad}, + } +} + +func keyOf(t *testing.T, id string, r *types.ReadResult) string { + t.Helper() + k, err := types.GetReadBallotKey(id, r) + require.NoError(t, err) + return k +} + +// Identical observations must converge, or quorum can never form. +func TestGetReadBallotKey_IdenticalObservationsAgree(t *testing.T) { + require.Equal(t, keyOf(t, "0xaa", result()), keyOf(t, "0xaa", result())) +} + +// Every consensus-relevant field must move the key. If one did not, validators +// could finalize a ballot while disagreeing about that field. +func TestGetReadBallotKey_EveryFieldIsBinding(t *testing.T) { + base := keyOf(t, "0xaa", result()) + + for name, mutate := range map[string]func(*types.ReadResult){ + "status": func(r *types.ReadResult) { r.Status = types.ReadStatus_READ_STATUS_ERROR }, + "result_data": func(r *types.ReadResult) { r.ResultData = []byte{0x01} }, + } { + t.Run(name, func(t *testing.T) { + r := result() + mutate(r) + require.NotEqual(t, base, keyOf(t, "0xaa", r), + "%s must change the ballot key", name) + }) + } + + // and the request id itself + require.NotEqual(t, base, keyOf(t, "0xbb", result())) +} + +// Aggregates are reserved for v2 MEDIAN and must NOT participate. Hashing them now +// would make the v2 rollout consensus-breaking: the same read would map to a +// different ballot before and after aggregates start being populated. +func TestGetReadBallotKey_ExcludesAggregates(t *testing.T) { + withAgg := result() + withAgg.Aggregates = []*types.AggregateValue{ + {ExtractIndex: 0, Mode: 1, Value: []byte{0x09}}, + } + + require.Equal(t, keyOf(t, "0xaa", result()), keyOf(t, "0xaa", withAgg), + "aggregates must not affect the ballot key") +} + +// Field boundaries must not be forgeable by embedding the join character. +func TestGetReadBallotKey_FieldsCannotBleed(t *testing.T) { + a := result() + a.ResultData = []byte("A:B") + b := result() + b.ResultData = []byte("A") + + require.NotEqual(t, keyOf(t, "0xaa", a), keyOf(t, "0xaa", b)) +} + +// Request ids differing only in case are the same request. +func TestGetReadBallotKey_RequestIDCaseInsensitive(t *testing.T) { + require.Equal(t, keyOf(t, "0xAABB", result()), keyOf(t, "0xaabb", result())) +} + +func TestGetReadBallotKey_Rejects(t *testing.T) { + _, err := types.GetReadBallotKey("", result()) + require.Error(t, err) + + _, err = types.GetReadBallotKey("0xaa", nil) + require.Error(t, err) +} + +// The ballot's deadline must land exactly on the request's, since x/uvalidator +// stores expiry as created + delta while the request carries an absolute height. +func TestBallotExpiryAfterBlocks_LandsOnRequestDeadline(t *testing.T) { + for _, tc := range []struct { + name string + expiry uint64 + current int64 + want int64 + }{ + {"future deadline", 500, 100, 400}, + {"next block", 101, 100, 1}, + {"from genesis", 900_000, 0, 900_000}, + } { + t.Run(tc.name, func(t *testing.T) { + got := types.BallotExpiryAfterBlocks(tc.expiry, tc.current) + require.Equal(t, tc.want, got) + require.Equal(t, int64(tc.expiry), tc.current+got, + "created + delta must equal the request's own deadline") + }) + } +} + +// A ballot must never be born already expired, even if the caller slipped a +// past-deadline request through. +func TestBallotExpiryAfterBlocks_NeverBornExpired(t *testing.T) { + for _, tc := range []struct { + expiry uint64 + current int64 + }{ + {100, 100}, // exactly at the deadline + {50, 100}, // past it + {0, 100}, // unset + } { + require.Equal(t, int64(1), types.BallotExpiryAfterBlocks(tc.expiry, tc.current), + "expiry=%d current=%d", tc.expiry, tc.current) + } +} + +// Empty and nil byte fields must hash identically, or validators reporting the +// same ERROR would split across ballots depending on how their client happened to +// represent "no data". A placeholder byte must NOT be treated as empty. +func TestGetReadBallotKey_EmptyBytesAreCanonical(t *testing.T) { + key := func(data []byte) string { + k, err := types.GetReadBallotKey("0xaa", &types.ReadResult{ + Status: types.ReadStatus_READ_STATUS_ERROR, + ResultData: data, + }) + require.NoError(t, err) + return k + } + + canonical := key(nil) + require.Equal(t, canonical, key([]byte{}), "empty slice == nil") + require.Equal(t, canonical, key([]byte("")), `[]byte("") == nil`) + + // A single zero byte is data, not absence — a validator that zero-fills would + // land on its own ballot and quorum would never form. + require.NotEqual(t, canonical, key([]byte{0x00}), + "a placeholder byte must not be mistaken for empty") +} + +// Disagreement about WHY a read failed is real disagreement, so the code must move +// the ballot key — otherwise REVERTED and NOT_FOUND would collapse onto one ballot. +func TestGetReadBallotKey_ErrorCodeIsBinding(t *testing.T) { + errResult := func(code types.ReadErrorCode) *types.ReadResult { + return &types.ReadResult{Status: types.ReadStatus_READ_STATUS_ERROR, ErrorCode: code} + } + + seen := map[string]types.ReadErrorCode{} + for _, code := range []types.ReadErrorCode{ + types.ReadErrorCode_READ_ERROR_UNSPECIFIED, + types.ReadErrorCode_READ_ERROR_INVALID_QUERY, + types.ReadErrorCode_READ_ERROR_UNSUPPORTED, + types.ReadErrorCode_READ_ERROR_REVERTED, + types.ReadErrorCode_READ_ERROR_NOT_FOUND, + types.ReadErrorCode_READ_ERROR_INVALID_RESULT, + types.ReadErrorCode_READ_ERROR_REJECTED, + } { + k := keyOf(t, "0xaa", errResult(code)) + if prev, dup := seen[k]; dup { + t.Fatalf("%s and %s collide on one ballot", code, prev) + } + seen[k] = code + } + require.Len(t, seen, 7, "every error code must be its own ballot") +} + +// Shapes that could never be produced by two honest validators alike are rejected +// at submission, so an operator sees an error instead of a ballot that silently +// never reaches quorum. +func TestValidateReadResult(t *testing.T) { + + for name, tc := range map[string]struct { + result *types.ReadResult + valid bool + }{ + "success": {&types.ReadResult{ + Status: types.ReadStatus_READ_STATUS_SUCCESS, ResultData: []byte{1}}, true}, + "success, empty data": {&types.ReadResult{ + Status: types.ReadStatus_READ_STATUS_SUCCESS}, true}, + "error with code": {&types.ReadResult{ + Status: types.ReadStatus_READ_STATUS_ERROR, + ErrorCode: types.ReadErrorCode_READ_ERROR_REVERTED}, true}, + "error without code": {&types.ReadResult{ + Status: types.ReadStatus_READ_STATUS_ERROR}, true}, + + "nil": {nil, false}, + "unspecified status": {&types.ReadResult{}, false}, + "success carrying an error code": {&types.ReadResult{ + Status: types.ReadStatus_READ_STATUS_SUCCESS, + ErrorCode: types.ReadErrorCode_READ_ERROR_REVERTED}, false}, + "error carrying result data": {&types.ReadResult{ + Status: types.ReadStatus_READ_STATUS_ERROR, ResultData: []byte{1}}, false}, + "v1 aggregates": {&types.ReadResult{ + Status: types.ReadStatus_READ_STATUS_SUCCESS, + Aggregates: []*types.AggregateValue{{Mode: 1}}}, false}, + } { + t.Run(name, func(t *testing.T) { + err := types.ValidateReadResult(tc.result) + if tc.valid { + require.NoError(t, err) + } else { + require.Error(t, err) + } + }) + } +} + +// Classification decides whether a failed call may be treated as terminal. Getting +// it wrong in the "already settled" direction strands the funder's deposit, since +// only the module can call expireExternalRead. +func TestClassifyCall(t *testing.T) { + sel := func(sig string) []byte { return crypto.Keccak256([]byte(sig))[:4] } + + for name, tc := range map[string]struct { + vmError string + revertData []byte + callErr error + want types.CallOutcome + }{ + "success": {"", nil, nil, types.CallOK}, + "success ignores stale data": {"", sel("TransferFailed()"), nil, types.CallOK}, + + "invalid callback target": {"execution reverted", sel("InvalidCallbackTarget()"), nil, types.CallAlreadySettled}, + + "out of gas": {"out of gas", nil, nil, types.CallOutOfGas}, + "code store out of gas": {"contract creation code storage out of gas", nil, nil, types.CallOutOfGas}, + + "wrong module": {"execution reverted", sel("CallerIsNotUCallbackModule()"), nil, types.CallUnsettled}, + "not yet expired": {"execution reverted", sel("RequestNotYetExpired()"), nil, types.CallUnsettled}, + "vault refused": {"execution reverted", sel("TransferFailed()"), nil, types.CallUnsettled}, + "unknown revert": {"execution reverted", sel("SomethingElse()"), nil, types.CallUnsettled}, + "revert with no data": {"execution reverted", nil, nil, types.CallUnsettled}, + "truncated revert data": {"execution reverted", []byte{0x01, 0x02}, nil, types.CallUnsettled}, + "dispatch error": {"", nil, errTestTypes, types.CallUnsettled}, + } { + t.Run(name, func(t *testing.T) { + require.Equal(t, tc.want, + types.ClassifyCall(tc.vmError, tc.revertData, tc.callErr)) + }) + } +} + +// An unrecognised revert must never be read as "settled" — that is the direction +// that loses money. +func TestClassifyCall_UnknownRevertIsNeverSettled(t *testing.T) { + for _, sig := range []string{"Foo()", "Bar(uint256)", "Paused()", "ZeroAddress()"} { + got := types.ClassifyCall("execution reverted", crypto.Keccak256([]byte(sig))[:4], nil) + require.Equal(t, types.CallUnsettled, got, sig) + } +} + +var errTestTypes = errors.New("injected") + +// InvalidRequestStatus replaced RequestAlreadyFulfilled, and it carries the actual +// status. Only SETTLED and EXPIRED are terminal — EXECUTED means the callback ran +// but reportCallbackGas has not, so the budget is still escrowed and the funder is +// still owed a refund. +func TestClassifyCall_InvalidRequestStatus(t *testing.T) { + selector := crypto.Keccak256([]byte("InvalidRequestStatus(uint256,uint8,uint8)"))[:4] + + encode := func(actual uint8) []byte { + word := func(v uint64) []byte { + b := make([]byte, 32) + b[31] = byte(v) + return b + } + out := append([]byte{}, selector...) + out = append(out, word(0xaa)...) // requestId + out = append(out, word(uint64(actual))...) // actual + out = append(out, word(1)...) // expected = PENDING + return out + } + + for name, tc := range map[string]struct { + actual uint8 + want types.CallOutcome + }{ + "NONE — never existed": {0, types.CallUnsettled}, + "PENDING — nothing happened yet": {1, types.CallUnsettled}, + "EXECUTED — budget still escrowed": {2, types.CallUnsettled}, + "SETTLED — finished": {3, types.CallAlreadySettled}, + "EXPIRED — finished": {4, types.CallAlreadySettled}, + } { + t.Run(name, func(t *testing.T) { + require.Equal(t, tc.want, + types.ClassifyCall("execution reverted", encode(tc.actual), nil)) + }) + } + + // undecodable args must fall to the safe side + require.Equal(t, types.CallUnsettled, + types.ClassifyCall("execution reverted", selector, nil)) +} + +// DerivedEVMCall returns a response AND an error when the EVM reverts, so +// classification must read vmError before callErr. Checking the error first would +// discard the revert data and make CallAlreadySettled unreachable in production — +// every revert would look like "nothing settled". +func TestClassifyCall_RevertCarriesBothResponseAndError(t *testing.T) { + sel := func(sig string) []byte { return crypto.Keccak256([]byte(sig))[:4] } + wrapped := errors.New("failed to execute message; message index: 0: execution reverted") + + settled := append(sel("InvalidRequestStatus(uint256,uint8,uint8)"), + make([]byte, 96)...) + settled[4+63] = 3 // actual = SETTLED + settled[4+95] = 1 // expected = PENDING + + require.Equal(t, types.CallAlreadySettled, + types.ClassifyCall("execution reverted", settled, wrapped), + "an accompanying error must not mask the revert reason") + + require.Equal(t, types.CallOutOfGas, + types.ClassifyCall("out of gas", nil, wrapped)) + + // only a revert-free failure is a true no-execution case + require.Equal(t, types.CallUnsettled, + types.ClassifyCall("", nil, wrapped)) +} diff --git a/x/ucallback/types/callback_abi.go b/x/ucallback/types/callback_abi.go new file mode 100644 index 00000000..16330515 --- /dev/null +++ b/x/ucallback/types/callback_abi.go @@ -0,0 +1,241 @@ +package types + +import ( + "fmt" + "strings" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/core/vm" +) + +// Method names on UniversalCallback. All are module-gated: the contract admits +// only the x/ucallback module account as caller. +const ( + MethodFulfillExternalCallback = "fulfillExternalCallback" + + // MethodReportCallbackGas settles an EXECUTED request against the gas its + // callback consumed, and returns that figure clamped to the request's budget. + MethodReportCallbackGas = "reportCallbackGas" + + MethodExpireExternalRead = "expireExternalRead" +) + +// universalCallbackABI covers only the module-gated entry points x/ucallback calls, +// plus the custom errors it must tell apart. Transcribed from +// push-chain-core-contracts src/UniversalCallback.sol and src/libraries/Errors.sol. +// +// Deliberately not the full contract ABI: everything else on UniversalCallback is +// either user-facing or read-only, and a narrower fragment is one less thing to +// keep in sync with the contract. +const universalCallbackABI = `[ + { + "type": "function", + "name": "fulfillExternalCallback", + "stateMutability": "nonpayable", + "inputs": [ + {"name": "requestId", "type": "uint256"}, + {"name": "resultData", "type": "bytes"} + ], + "outputs": [] + }, + { + "type": "function", + "name": "reportCallbackGas", + "stateMutability": "nonpayable", + "inputs": [ + {"name": "requestId", "type": "uint256"}, + {"name": "gasBurned", "type": "uint256"} + ], + "outputs": [{"name": "burned", "type": "uint256"}] + }, + { + "type": "function", + "name": "expireExternalRead", + "stateMutability": "nonpayable", + "inputs": [{"name": "requestId", "type": "uint256"}], + "outputs": [] + }, + + {"type": "error", "name": "InvalidRequestStatus", "inputs": [ + {"name": "requestId", "type": "uint256"}, + {"name": "actual", "type": "uint8"}, + {"name": "expected", "type": "uint8"} + ]}, + {"type": "error", "name": "InvalidCallbackTarget", "inputs": []}, + {"type": "error", "name": "CallerIsNotUCallbackModule", "inputs": []}, + {"type": "error", "name": "RequestNotYetExpired", "inputs": []}, + {"type": "error", "name": "TransferFailed", "inputs": []} +]` + +var ( + parsedCallbackABI abi.ABI + + // Custom-error selectors, derived from the ABI rather than hardcoded so they + // cannot drift from the contract. A Solidity custom error reverts with + // keccak256(signature)[:4] followed by its ABI-encoded args, and that prefix is + // how we tell one revert from another. + errInvalidRequestStatus [4]byte + errInvalidCallbackTarget [4]byte + errCallerIsNotUCallbackModule [4]byte + errRequestNotYetExpired [4]byte + errTransferFailed [4]byte +) + +func init() { + parsed, err := abi.JSON(strings.NewReader(universalCallbackABI)) + if err != nil { + panic(fmt.Sprintf("ucallback: bad UniversalCallback ABI: %v", err)) + } + parsedCallbackABI = parsed + + sel := func(name string) [4]byte { + e, ok := parsed.Errors[name] + if !ok { + panic(fmt.Sprintf("ucallback: error %s missing from ABI", name)) + } + var out [4]byte + copy(out[:], e.ID[:4]) + return out + } + errInvalidRequestStatus = sel("InvalidRequestStatus") + errInvalidCallbackTarget = sel("InvalidCallbackTarget") + errCallerIsNotUCallbackModule = sel("CallerIsNotUCallbackModule") + errRequestNotYetExpired = sel("RequestNotYetExpired") + errTransferFailed = sel("TransferFailed") +} + +// ParseUniversalCallbackABI returns the parsed fragment for UniversalCallback. +func ParseUniversalCallbackABI() (abi.ABI, error) { + return parsedCallbackABI, nil +} + +// CallOutcome classifies what happened to a call into UniversalCallback, because +// the right response differs sharply between them — and the difference is invisible +// from "the call failed" alone. +type CallOutcome int + +const ( + // CallOK — the transaction succeeded. Note this includes the app's callback + // reverting: the contract catches that with .call, so the outer tx still + // succeeds and the request is settled. + CallOK CallOutcome = iota + + // CallAlreadySettled — RequestAlreadyFulfilled or InvalidCallbackTarget. The + // contract closed this request by another route and already ran _settle, so the + // funder has their refund. Nothing left to do; safe to mark terminal. + CallAlreadySettled + + // CallOutOfGas — the outer transaction ran out. Nothing persisted, but real gas + // was burned. The only outcome where the user's allowance was consumed without + // the contract recording it. + CallOutOfGas + + // CallUnsettled — everything else: wrong module address, the vault refusing the + // protocol fee, an intrinsic-gas rejection, a dispatch error. Nothing executed + // or nothing persisted, the deposit is still escrowed, and expiry must stay + // reachable so the funder can be refunded. + CallUnsettled +) + +func (o CallOutcome) String() string { + switch o { + case CallOK: + return "ok" + case CallAlreadySettled: + return "already_settled" + case CallOutOfGas: + return "out_of_gas" + default: + return "unsettled" + } +} + +// ClassifyCall maps a DerivedEVMCallWithData result onto a CallOutcome. +// +// vmError distinguishes out-of-gas ("out of gas") from a revert ("execution +// reverted"); revertData carries the custom error's 4-byte selector on a revert. +// Both come straight off MsgEthereumTxResponse. +func ClassifyCall(vmError string, revertData []byte, callErr error) CallOutcome { + // vmError is checked before callErr on purpose. The EVM call returns BOTH a + // response and an error when the EVM reverts (call_evm.go:323 wraps res.Failed() + // in ErrVMExecution), so treating a non-nil error as "no response" would discard + // the revert data and make CallAlreadySettled unreachable. + if vmError == "" { + if callErr != nil { + // No execution at all — rejected before the EVM ran (intrinsic gas, + // nonce lookup, dispatch). + return CallUnsettled + } + return CallOK + } + if vmError == vm.ErrOutOfGas.Error() || vmError == vm.ErrCodeStoreOutOfGas.Error() { + return CallOutOfGas + } + + if len(revertData) >= 4 { + var sel [4]byte + copy(sel[:], revertData[:4]) + switch sel { + case errInvalidCallbackTarget: + return CallAlreadySettled + + case errInvalidRequestStatus: + // The request moved on, but not necessarily to a settled state. Decode + // the actual status rather than assuming: EXECUTED means the callback + // ran and the budget is still escrowed awaiting reportCallbackGas, so + // treating it as settled would abandon that money. + return classifyStatusRevert(revertData) + + case errCallerIsNotUCallbackModule, errRequestNotYetExpired, errTransferFailed: + return CallUnsettled + } + } + + // An unrecognised revert. Treated as unsettled on purpose: assuming the + // contract settled when it did not would strand the funder's deposit, while the + // reverse only costs a retry. + return CallUnsettled +} + +// RequestStatus mirrors the contract's lifecycle enum (ReadTypes.sol). NONE must +// stay zero: every never-created requestId reads as zero on-chain. +type RequestStatus uint8 + +const ( + RequestStatusNone RequestStatus = iota + RequestStatusPending + RequestStatusExecuted + RequestStatusSettled + RequestStatusExpired +) + +// classifyStatusRevert reads the `actual` status out of an InvalidRequestStatus +// revert and decides whether the request is genuinely finished. +// +// Only SETTLED and EXPIRED are terminal on the contract. EXECUTED is not: the +// callback ran but reportCallbackGas has not, so callbackBudget is still escrowed +// and the funder is still owed a refund — retiring our record there would leave +// nothing driving the report. +func classifyStatusRevert(revertData []byte) CallOutcome { + args, err := parsedCallbackABI.Errors["InvalidRequestStatus"].Inputs.Unpack(revertData[4:]) + if err != nil || len(args) < 2 { + // Undecodable: assume unsettled, the safe direction. + return CallUnsettled + } + actual, ok := args[1].(uint8) + if !ok { + return CallUnsettled + } + switch RequestStatus(actual) { + case RequestStatusSettled, RequestStatusExpired: + return CallAlreadySettled + default: + return CallUnsettled + } +} + +// CallerIsNotUCallbackModuleSelector exposes the access-control revert prefix so +// tests can assert which revert a call produced. The contract pairs itself with a +// single module address at construction; getting this wrong makes every callback +// fail, so it is worth asserting against the real deployed bytecode. +func CallerIsNotUCallbackModuleSelector() [4]byte { return errCallerIsNotUCallbackModule } diff --git a/x/ucallback/types/codec.go b/x/ucallback/types/codec.go new file mode 100755 index 00000000..6d57a9e3 --- /dev/null +++ b/x/ucallback/types/codec.go @@ -0,0 +1,35 @@ +package types + +import ( + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/codec/types" + cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/msgservice" +) + +var ( + amino = codec.NewLegacyAmino() + AminoCdc = codec.NewAminoCodec(amino) +) + +func init() { + RegisterLegacyAminoCodec(amino) + cryptocodec.RegisterCrypto(amino) + sdk.RegisterLegacyAminoCodec(amino) +} + +// RegisterLegacyAminoCodec registers concrete types on the LegacyAmino codec +func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { + cdc.RegisterConcrete(&MsgUpdateParams{}, ModuleName+"/MsgUpdateParams", nil) +} + +func RegisterInterfaces(registry types.InterfaceRegistry) { + + registry.RegisterImplementations( + (*sdk.Msg)(nil), + &MsgUpdateParams{}, + ) + + msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) +} diff --git a/x/ucallback/types/expected_keepers.go b/x/ucallback/types/expected_keepers.go new file mode 100644 index 00000000..be9e25a7 --- /dev/null +++ b/x/ucallback/types/expected_keepers.go @@ -0,0 +1,88 @@ +package types + +import ( + "context" + "math/big" + + "github.com/ethereum/go-ethereum/common" + + "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + evmtypes "github.com/cosmos/evm/x/vm/types" + + uvalidatortypes "github.com/pushchain/push-chain-node/x/uvalidator/types" +) + +// UValidatorKeeper is the slice of x/uvalidator that x/ucallback needs: the voter +// set and ballot primitive for read voting, the two eligibility checks, and the +// admin address that gates the expiry escape hatch. +type UValidatorKeeper interface { + IsBondedUniversalValidator(ctx context.Context, universalValidator string) (bool, error) + IsTombstonedUniversalValidator(ctx context.Context, universalValidator string) (bool, error) + GetEligibleVoters(ctx context.Context) ([]uvalidatortypes.UniversalValidator, error) + GetAdmin(ctx context.Context) (string, error) + VoteOnBallot( + ctx context.Context, + id string, + ballotType uvalidatortypes.BallotObservationType, + voter string, + voteResult uvalidatortypes.VoteResult, + voters []string, + votesNeeded int64, + expiryAfterBlocks int64, + ) ( + ballot uvalidatortypes.Ballot, + isFinalized bool, + isNew bool, + err error) +} + +// EVMKeeper is the slice of x/vm needed to call UniversalCallback. Only the +// derived-call entry point is required — reads never deploy or write state +// directly. +// +// DerivedEVMCallWithData, and deliberately NOT the ABI-typed DerivedEVMCall +// wrapper that sits above it. On a revert that wrapper returns (nil, err), +// discarding the response and with it res.Ret — the revert data ClassifyCall reads +// to tell "already settled" from "try again". Leaving it off this interface makes +// reaching for it a compile error rather than something a reviewer has to catch. +type EVMKeeper interface { + DerivedEVMCallWithData( + ctx sdk.Context, + from common.Address, + contract *common.Address, + data []byte, + commit, gasless, isModuleSender bool, + value, gasLimit *big.Int, + manualNonce *uint64, + ) (*evmtypes.MsgEthereumTxResponse, error) +} + +// AccountKeeper resolves the x/ucallback module account, whose address is the +// caller UniversalCallback's access control admits. +type AccountKeeper interface { + GetModuleAccount(ctx context.Context, moduleName string) sdk.ModuleAccountI +} + +// FeeMarketKeeper supplies the base fee used to price callback gas. Same source +// x/uexecutor uses in CalculateGasCost, so a read and a UEA execution are valued +// identically. +// +// Satisfied by a value, not a pointer to the app field: the keeper is constructed +// after x/feemarket, so there is nothing left to populate. +type FeeMarketKeeper interface { + GetBaseFee(ctx sdk.Context) math.LegacyDec +} + +// BankKeeper covers moving the consumed callback budget out of the contract and +// destroying it. +// +// The contract deliberately leaves itself over-collateralised by the burned amount +// after reportCallbackGas, expecting the module to take it. A contract's balance is +// an ordinary bank balance, so this needs no contract-side API — the same shape as +// x/uexecutor's DeductAndBurnFees. +type BankKeeper interface { + SendCoinsFromAccountToModule(ctx context.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error + BurnCoins(ctx context.Context, moduleName string, amt sdk.Coins) error + GetBalance(ctx context.Context, addr sdk.AccAddress, denom string) sdk.Coin +} diff --git a/x/ucallback/types/genesis.go b/x/ucallback/types/genesis.go new file mode 100755 index 00000000..97cad761 --- /dev/null +++ b/x/ucallback/types/genesis.go @@ -0,0 +1,19 @@ +package types + +// DefaultIndex is the default global index +const DefaultIndex uint64 = 1 + +// DefaultGenesis returns the default genesis state +func DefaultGenesis() *GenesisState { + return &GenesisState{ + + Params: DefaultParams(), + } +} + +// Validate performs basic genesis state validation returning an error upon any +// failure. +func (gs GenesisState) Validate() error { + + return gs.Params.Validate() +} diff --git a/x/ucallback/types/genesis.pb.go b/x/ucallback/types/genesis.pb.go new file mode 100644 index 00000000..3a0a6019 --- /dev/null +++ b/x/ucallback/types/genesis.pb.go @@ -0,0 +1,851 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: ucallback/v1/genesis.proto + +package types + +import ( + fmt "fmt" + _ "github.com/cosmos/cosmos-sdk/types/tx/amino" + _ "github.com/cosmos/gogoproto/gogoproto" + proto "github.com/cosmos/gogoproto/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// GenesisState defines the module genesis state +type GenesisState struct { + // Params defines all the parameters of the module. + Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` + // universal_reads are key-value pairs from the UniversalReads map. + // + // Only the canonical records are exported. PendingByExpiry and ReadsByTxHash + // are indexes derived from these, and are rebuilt during InitGenesis rather + // than exported — so they cannot be imported out of sync with the records they + // point at. + UniversalReads []UniversalReadEntry `protobuf:"bytes,2,rep,name=universal_reads,json=universalReads,proto3" json:"universal_reads"` + // module_account_nonce is the EVM nonce of the x/ucallback module account. + // + // Must round-trip through genesis: it is the nonce of a real EVM account, and + // exporting state without it would make every module call after an import reuse + // nonces the chain had already consumed. + ModuleAccountNonce uint64 `protobuf:"varint,3,opt,name=module_account_nonce,json=moduleAccountNonce,proto3" json:"module_account_nonce,omitempty"` +} + +func (m *GenesisState) Reset() { *m = GenesisState{} } +func (m *GenesisState) String() string { return proto.CompactTextString(m) } +func (*GenesisState) ProtoMessage() {} +func (*GenesisState) Descriptor() ([]byte, []int) { + return fileDescriptor_13c1287495624272, []int{0} +} +func (m *GenesisState) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GenesisState) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GenesisState.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *GenesisState) XXX_Merge(src proto.Message) { + xxx_messageInfo_GenesisState.Merge(m, src) +} +func (m *GenesisState) XXX_Size() int { + return m.Size() +} +func (m *GenesisState) XXX_DiscardUnknown() { + xxx_messageInfo_GenesisState.DiscardUnknown(m) +} + +var xxx_messageInfo_GenesisState proto.InternalMessageInfo + +func (m *GenesisState) GetParams() Params { + if m != nil { + return m.Params + } + return Params{} +} + +func (m *GenesisState) GetUniversalReads() []UniversalReadEntry { + if m != nil { + return m.UniversalReads + } + return nil +} + +func (m *GenesisState) GetModuleAccountNonce() uint64 { + if m != nil { + return m.ModuleAccountNonce + } + return 0 +} + +// UniversalReadEntry is one key-value pair from the UniversalReads map. +type UniversalReadEntry struct { + Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` + Value UniversalRead `protobuf:"bytes,2,opt,name=value,proto3" json:"value"` +} + +func (m *UniversalReadEntry) Reset() { *m = UniversalReadEntry{} } +func (m *UniversalReadEntry) String() string { return proto.CompactTextString(m) } +func (*UniversalReadEntry) ProtoMessage() {} +func (*UniversalReadEntry) Descriptor() ([]byte, []int) { + return fileDescriptor_13c1287495624272, []int{1} +} +func (m *UniversalReadEntry) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *UniversalReadEntry) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_UniversalReadEntry.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *UniversalReadEntry) XXX_Merge(src proto.Message) { + xxx_messageInfo_UniversalReadEntry.Merge(m, src) +} +func (m *UniversalReadEntry) XXX_Size() int { + return m.Size() +} +func (m *UniversalReadEntry) XXX_DiscardUnknown() { + xxx_messageInfo_UniversalReadEntry.DiscardUnknown(m) +} + +var xxx_messageInfo_UniversalReadEntry proto.InternalMessageInfo + +func (m *UniversalReadEntry) GetKey() string { + if m != nil { + return m.Key + } + return "" +} + +func (m *UniversalReadEntry) GetValue() UniversalRead { + if m != nil { + return m.Value + } + return UniversalRead{} +} + +// Params defines the set of module parameters. +type Params struct { + SomeValue bool `protobuf:"varint,2,opt,name=some_value,json=someValue,proto3" json:"some_value,omitempty"` +} + +func (m *Params) Reset() { *m = Params{} } +func (*Params) ProtoMessage() {} +func (*Params) Descriptor() ([]byte, []int) { + return fileDescriptor_13c1287495624272, []int{2} +} +func (m *Params) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Params) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Params.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Params) XXX_Merge(src proto.Message) { + xxx_messageInfo_Params.Merge(m, src) +} +func (m *Params) XXX_Size() int { + return m.Size() +} +func (m *Params) XXX_DiscardUnknown() { + xxx_messageInfo_Params.DiscardUnknown(m) +} + +var xxx_messageInfo_Params proto.InternalMessageInfo + +func (m *Params) GetSomeValue() bool { + if m != nil { + return m.SomeValue + } + return false +} + +func init() { + proto.RegisterType((*GenesisState)(nil), "ucallback.v1.GenesisState") + proto.RegisterType((*UniversalReadEntry)(nil), "ucallback.v1.UniversalReadEntry") + proto.RegisterType((*Params)(nil), "ucallback.v1.Params") +} + +func init() { proto.RegisterFile("ucallback/v1/genesis.proto", fileDescriptor_13c1287495624272) } + +var fileDescriptor_13c1287495624272 = []byte{ + // 386 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x2a, 0x4d, 0x4e, 0xcc, + 0xc9, 0x49, 0x4a, 0x4c, 0xce, 0xd6, 0x2f, 0x33, 0xd4, 0x4f, 0x4f, 0xcd, 0x4b, 0x2d, 0xce, 0x2c, + 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x81, 0xcb, 0xe9, 0x95, 0x19, 0x4a, 0x89, 0xa4, + 0xe7, 0xa7, 0xe7, 0x83, 0x25, 0xf4, 0x41, 0x2c, 0x88, 0x1a, 0x29, 0xc1, 0xc4, 0xdc, 0xcc, 0xbc, + 0x7c, 0x7d, 0x30, 0x09, 0x15, 0x92, 0x40, 0x31, 0xb2, 0xa4, 0xb2, 0x20, 0x15, 0x6a, 0xa0, 0xd2, + 0x51, 0x46, 0x2e, 0x1e, 0x77, 0x88, 0x15, 0xc1, 0x25, 0x89, 0x25, 0xa9, 0x42, 0x46, 0x5c, 0x6c, + 0x05, 0x89, 0x45, 0x89, 0xb9, 0xc5, 0x12, 0x8c, 0x0a, 0x8c, 0x1a, 0xdc, 0x46, 0x22, 0x7a, 0xc8, + 0x56, 0xea, 0x05, 0x80, 0xe5, 0x9c, 0x58, 0x4e, 0xdc, 0x93, 0x67, 0x08, 0x82, 0xaa, 0x14, 0xf2, + 0xe7, 0xe2, 0x2f, 0xcd, 0xcb, 0x2c, 0x4b, 0x2d, 0x2a, 0x4e, 0xcc, 0x89, 0x2f, 0x4a, 0x4d, 0x4c, + 0x29, 0x96, 0x60, 0x52, 0x60, 0xd6, 0xe0, 0x36, 0x52, 0x40, 0xd5, 0x1c, 0x0a, 0x53, 0x14, 0x94, + 0x9a, 0x98, 0xe2, 0x9a, 0x57, 0x52, 0x54, 0x09, 0x35, 0x88, 0xaf, 0x14, 0x59, 0xa6, 0x58, 0xc8, + 0x80, 0x4b, 0x24, 0x37, 0x3f, 0xa5, 0x34, 0x27, 0x35, 0x3e, 0x31, 0x39, 0x39, 0xbf, 0x34, 0xaf, + 0x24, 0x3e, 0x2f, 0x3f, 0x2f, 0x39, 0x55, 0x82, 0x59, 0x81, 0x51, 0x83, 0x25, 0x48, 0x08, 0x22, + 0xe7, 0x08, 0x91, 0xf2, 0x03, 0xc9, 0x28, 0xc5, 0x73, 0x09, 0x61, 0x9a, 0x2e, 0x24, 0xc0, 0xc5, + 0x9c, 0x9d, 0x5a, 0x09, 0xf6, 0x09, 0x67, 0x10, 0x88, 0x29, 0x64, 0xce, 0xc5, 0x5a, 0x96, 0x98, + 0x53, 0x9a, 0x2a, 0xc1, 0x04, 0xf6, 0x9d, 0x34, 0x1e, 0x07, 0x42, 0xdd, 0x06, 0x51, 0xaf, 0xe4, + 0xc6, 0xc5, 0x06, 0xf1, 0xbb, 0x90, 0x2c, 0x17, 0x57, 0x71, 0x7e, 0x6e, 0x6a, 0x3c, 0xc2, 0x1c, + 0x8e, 0x20, 0x4e, 0x90, 0x48, 0x18, 0x48, 0xc0, 0x4a, 0x76, 0xc6, 0x02, 0x79, 0x86, 0x17, 0x0b, + 0xe4, 0x19, 0xbb, 0x9e, 0x6f, 0xd0, 0x12, 0x40, 0x04, 0x3c, 0x24, 0xac, 0x9c, 0x02, 0x4e, 0x3c, + 0x92, 0x63, 0xbc, 0xf0, 0x48, 0x8e, 0xf1, 0xc1, 0x23, 0x39, 0xc6, 0x09, 0x8f, 0xe5, 0x18, 0x2e, + 0x3c, 0x96, 0x63, 0xb8, 0xf1, 0x58, 0x8e, 0x21, 0xca, 0x2c, 0x3d, 0xb3, 0x24, 0xa3, 0x34, 0x49, + 0x2f, 0x39, 0x3f, 0x57, 0xbf, 0xa0, 0xb4, 0x38, 0x23, 0x39, 0x23, 0x31, 0x33, 0x0f, 0xcc, 0xd2, + 0x05, 0x33, 0x75, 0xf3, 0xf2, 0x53, 0x52, 0xf5, 0x2b, 0xf4, 0x11, 0x46, 0x82, 0x23, 0x32, 0x89, + 0x0d, 0x1c, 0x93, 0xc6, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0xdc, 0x07, 0xc1, 0x4d, 0x38, 0x02, + 0x00, 0x00, +} + +func (this *Params) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*Params) + if !ok { + that2, ok := that.(Params) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.SomeValue != that1.SomeValue { + return false + } + return true +} +func (m *GenesisState) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GenesisState) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.ModuleAccountNonce != 0 { + i = encodeVarintGenesis(dAtA, i, uint64(m.ModuleAccountNonce)) + i-- + dAtA[i] = 0x18 + } + if len(m.UniversalReads) > 0 { + for iNdEx := len(m.UniversalReads) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.UniversalReads[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + { + size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *UniversalReadEntry) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *UniversalReadEntry) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *UniversalReadEntry) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Value.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if len(m.Key) > 0 { + i -= len(m.Key) + copy(dAtA[i:], m.Key) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.Key))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *Params) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Params) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.SomeValue { + i-- + if m.SomeValue { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x10 + } + return len(dAtA) - i, nil +} + +func encodeVarintGenesis(dAtA []byte, offset int, v uint64) int { + offset -= sovGenesis(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *GenesisState) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Params.Size() + n += 1 + l + sovGenesis(uint64(l)) + if len(m.UniversalReads) > 0 { + for _, e := range m.UniversalReads { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + if m.ModuleAccountNonce != 0 { + n += 1 + sovGenesis(uint64(m.ModuleAccountNonce)) + } + return n +} + +func (m *UniversalReadEntry) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Key) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + l = m.Value.Size() + n += 1 + l + sovGenesis(uint64(l)) + return n +} + +func (m *Params) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.SomeValue { + n += 2 + } + return n +} + +func sovGenesis(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozGenesis(x uint64) (n int) { + return sovGenesis(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *GenesisState) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GenesisState: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GenesisState: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Params", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Params.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field UniversalReads", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.UniversalReads = append(m.UniversalReads, UniversalReadEntry{}) + if err := m.UniversalReads[len(m.UniversalReads)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ModuleAccountNonce", wireType) + } + m.ModuleAccountNonce = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ModuleAccountNonce |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *UniversalReadEntry) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: UniversalReadEntry: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: UniversalReadEntry: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Key", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Key = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Value", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Value.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Params) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Params: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Params: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field SomeValue", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.SomeValue = bool(v != 0) + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipGenesis(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthGenesis + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupGenesis + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthGenesis + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthGenesis = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowGenesis = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupGenesis = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/ucallback/types/genesis_test.go b/x/ucallback/types/genesis_test.go new file mode 100755 index 00000000..4b2c37e4 --- /dev/null +++ b/x/ucallback/types/genesis_test.go @@ -0,0 +1,38 @@ +package types_test + +import ( + "testing" + + "github.com/pushchain/push-chain-node/x/ucallback/types" + + "github.com/stretchr/testify/require" +) + +func TestGenesisState_Validate(t *testing.T) { + tests := []struct { + desc string + genState *types.GenesisState + valid bool + }{ + { + desc: "default is valid", + genState: types.DefaultGenesis(), + valid: true, + }, + { + desc: "valid genesis state", + genState: &types.GenesisState{}, + valid: true, + }, + } + for _, tc := range tests { + t.Run(tc.desc, func(t *testing.T) { + err := tc.genState.Validate() + if tc.valid { + require.NoError(t, err) + } else { + require.Error(t, err) + } + }) + } +} diff --git a/x/ucallback/types/keys.go b/x/ucallback/types/keys.go new file mode 100755 index 00000000..38818a70 --- /dev/null +++ b/x/ucallback/types/keys.go @@ -0,0 +1,47 @@ +package types + +import ( + "cosmossdk.io/collections" +) + +var ( + // ParamsKey saves the current module params. + ParamsKey = collections.NewPrefix(0) + + // UniversalReadsKey is the canonical record for every read request, + // keyed by requestId. Everything else in this module is an index over it. + UniversalReadsKey = collections.NewPrefix(1) + + // PendingByExpiryKey indexes unsettled reads by the Push Chain height they + // expire at. Key is (expiryHeight, requestId). Entries are removed the moment + // a read settles, which makes this the module's set of in-flight work. + PendingByExpiryKey = collections.NewPrefix(2) + + // ReadsByTxHashKey indexes reads by the Push Chain tx that requested them. + // One transaction can emit several ReadRequested logs; each becomes its own + // UniversalRead, and this index is what reassembles the batch. + // Key is (pushTxHash, requestId). + ReadsByTxHashKey = collections.NewPrefix(3) + + // ModuleAccountNonceKey tracks the EVM nonce of the x/ucallback module + // account. x/ucallback owns this counter because it owns the account: the + // UniversalCallback contract's access control is keyed to this module's + // address, so no other module ever sends from it. + // AbortedReadsKey indexes reads the chain gave up on — expiry that never + // landed after MaxExpiryAttempts. Small and operationally meaningful: these are + // exactly the requests needing manual intervention, and enumerating them by + // scanning UniversalReads would mean walking every read the chain has ever + // seen. Mirrors x/uexecutor's ExpiredInbounds. + AbortedReadsKey = collections.NewPrefix(5) + + ModuleAccountNonceKey = collections.NewPrefix(4) + ModuleAccountNonceName = "module_account_nonce" +) + +const ( + ModuleName = "ucallback" + + StoreKey = ModuleName + + QuerierRoute = ModuleName +) diff --git a/x/ucallback/types/msgs.go b/x/ucallback/types/msgs.go new file mode 100755 index 00000000..360797d6 --- /dev/null +++ b/x/ucallback/types/msgs.go @@ -0,0 +1,49 @@ +package types + +import ( + "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +var ( + _ sdk.Msg = &MsgUpdateParams{} +) + +// NewMsgUpdateParams creates new instance of MsgUpdateParams +func NewMsgUpdateParams( + sender sdk.Address, + someValue bool, +) *MsgUpdateParams { + return &MsgUpdateParams{ + Authority: sender.String(), + Params: Params{ + SomeValue: someValue, + }, + } +} + +// Route returns the name of the module +func (msg MsgUpdateParams) Route() string { return ModuleName } + +// Type returns the the action +func (msg MsgUpdateParams) Type() string { return "update_params" } + +// GetSignBytes implements the LegacyMsg interface. +func (msg MsgUpdateParams) GetSignBytes() []byte { + return sdk.MustSortJSON(AminoCdc.MustMarshalJSON(&msg)) +} + +// GetSigners returns the expected signers for a MsgUpdateParams message. +func (msg *MsgUpdateParams) GetSigners() []sdk.AccAddress { + addr, _ := sdk.AccAddressFromBech32(msg.Authority) + return []sdk.AccAddress{addr} +} + +// ValidateBasic does a sanity check on the provided data. +func (msg *MsgUpdateParams) Validate() error { + if _, err := sdk.AccAddressFromBech32(msg.Authority); err != nil { + return errors.Wrap(err, "invalid authority address") + } + + return msg.Params.Validate() +} diff --git a/x/ucallback/types/params.go b/x/ucallback/types/params.go new file mode 100755 index 00000000..d9be77ae --- /dev/null +++ b/x/ucallback/types/params.go @@ -0,0 +1,29 @@ +package types + +import ( + "encoding/json" +) + +// DefaultParams returns default module parameters. +func DefaultParams() Params { + // TODO: + return Params{ + SomeValue: true, + } +} + +// Stringer method for Params. +func (p Params) String() string { + bz, err := json.Marshal(p) + if err != nil { + panic(err) + } + + return string(bz) +} + +// Validate does the sanity check on the params. +func (p Params) Validate() error { + // TODO: + return nil +} diff --git a/x/ucallback/types/query.pb.go b/x/ucallback/types/query.pb.go new file mode 100644 index 00000000..cffebe58 --- /dev/null +++ b/x/ucallback/types/query.pb.go @@ -0,0 +1,2265 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: ucallback/v1/query.proto + +package types + +import ( + context "context" + fmt "fmt" + query "github.com/cosmos/cosmos-sdk/types/query" + _ "github.com/cosmos/gogoproto/gogoproto" + grpc1 "github.com/cosmos/gogoproto/grpc" + proto "github.com/cosmos/gogoproto/proto" + _ "google.golang.org/genproto/googleapis/api/annotations" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// QueryParamsRequest is the request type for the Query/Params RPC method. +type QueryParamsRequest struct { +} + +func (m *QueryParamsRequest) Reset() { *m = QueryParamsRequest{} } +func (m *QueryParamsRequest) String() string { return proto.CompactTextString(m) } +func (*QueryParamsRequest) ProtoMessage() {} +func (*QueryParamsRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_a64b97cfcca36b9d, []int{0} +} +func (m *QueryParamsRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryParamsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryParamsRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryParamsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryParamsRequest.Merge(m, src) +} +func (m *QueryParamsRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryParamsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryParamsRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryParamsRequest proto.InternalMessageInfo + +// QueryParamsResponse is the response type for the Query/Params RPC method. +type QueryParamsResponse struct { + // params defines the parameters of the module. + Params *Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params,omitempty"` +} + +func (m *QueryParamsResponse) Reset() { *m = QueryParamsResponse{} } +func (m *QueryParamsResponse) String() string { return proto.CompactTextString(m) } +func (*QueryParamsResponse) ProtoMessage() {} +func (*QueryParamsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_a64b97cfcca36b9d, []int{1} +} +func (m *QueryParamsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryParamsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryParamsResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryParamsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryParamsResponse.Merge(m, src) +} +func (m *QueryParamsResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryParamsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryParamsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryParamsResponse proto.InternalMessageInfo + +func (m *QueryParamsResponse) GetParams() *Params { + if m != nil { + return m.Params + } + return nil +} + +type QueryAllPendingReadRequestsRequest struct { + Pagination *query.PageRequest `protobuf:"bytes,1,opt,name=pagination,proto3" json:"pagination,omitempty"` +} + +func (m *QueryAllPendingReadRequestsRequest) Reset() { *m = QueryAllPendingReadRequestsRequest{} } +func (m *QueryAllPendingReadRequestsRequest) String() string { return proto.CompactTextString(m) } +func (*QueryAllPendingReadRequestsRequest) ProtoMessage() {} +func (*QueryAllPendingReadRequestsRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_a64b97cfcca36b9d, []int{2} +} +func (m *QueryAllPendingReadRequestsRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryAllPendingReadRequestsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryAllPendingReadRequestsRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryAllPendingReadRequestsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryAllPendingReadRequestsRequest.Merge(m, src) +} +func (m *QueryAllPendingReadRequestsRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryAllPendingReadRequestsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryAllPendingReadRequestsRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryAllPendingReadRequestsRequest proto.InternalMessageInfo + +func (m *QueryAllPendingReadRequestsRequest) GetPagination() *query.PageRequest { + if m != nil { + return m.Pagination + } + return nil +} + +type QueryAllPendingReadRequestsResponse struct { + // Reads that are unsettled AND not yet past their expiry height. Requests past + // expiry are withheld here even before the sweeper retires them, so validators + // never take on work that can no longer be fulfilled in time. + Reads []UniversalRead `protobuf:"bytes,1,rep,name=reads,proto3" json:"reads"` + Pagination *query.PageResponse `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination,omitempty"` +} + +func (m *QueryAllPendingReadRequestsResponse) Reset() { *m = QueryAllPendingReadRequestsResponse{} } +func (m *QueryAllPendingReadRequestsResponse) String() string { return proto.CompactTextString(m) } +func (*QueryAllPendingReadRequestsResponse) ProtoMessage() {} +func (*QueryAllPendingReadRequestsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_a64b97cfcca36b9d, []int{3} +} +func (m *QueryAllPendingReadRequestsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryAllPendingReadRequestsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryAllPendingReadRequestsResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryAllPendingReadRequestsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryAllPendingReadRequestsResponse.Merge(m, src) +} +func (m *QueryAllPendingReadRequestsResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryAllPendingReadRequestsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryAllPendingReadRequestsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryAllPendingReadRequestsResponse proto.InternalMessageInfo + +func (m *QueryAllPendingReadRequestsResponse) GetReads() []UniversalRead { + if m != nil { + return m.Reads + } + return nil +} + +func (m *QueryAllPendingReadRequestsResponse) GetPagination() *query.PageResponse { + if m != nil { + return m.Pagination + } + return nil +} + +type QueryUniversalReadRequest struct { + RequestId string `protobuf:"bytes,1,opt,name=request_id,json=requestId,proto3" json:"request_id,omitempty"` +} + +func (m *QueryUniversalReadRequest) Reset() { *m = QueryUniversalReadRequest{} } +func (m *QueryUniversalReadRequest) String() string { return proto.CompactTextString(m) } +func (*QueryUniversalReadRequest) ProtoMessage() {} +func (*QueryUniversalReadRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_a64b97cfcca36b9d, []int{4} +} +func (m *QueryUniversalReadRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryUniversalReadRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryUniversalReadRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryUniversalReadRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryUniversalReadRequest.Merge(m, src) +} +func (m *QueryUniversalReadRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryUniversalReadRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryUniversalReadRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryUniversalReadRequest proto.InternalMessageInfo + +func (m *QueryUniversalReadRequest) GetRequestId() string { + if m != nil { + return m.RequestId + } + return "" +} + +type QueryUniversalReadResponse struct { + Read UniversalRead `protobuf:"bytes,1,opt,name=read,proto3" json:"read"` +} + +func (m *QueryUniversalReadResponse) Reset() { *m = QueryUniversalReadResponse{} } +func (m *QueryUniversalReadResponse) String() string { return proto.CompactTextString(m) } +func (*QueryUniversalReadResponse) ProtoMessage() {} +func (*QueryUniversalReadResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_a64b97cfcca36b9d, []int{5} +} +func (m *QueryUniversalReadResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryUniversalReadResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryUniversalReadResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryUniversalReadResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryUniversalReadResponse.Merge(m, src) +} +func (m *QueryUniversalReadResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryUniversalReadResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryUniversalReadResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryUniversalReadResponse proto.InternalMessageInfo + +func (m *QueryUniversalReadResponse) GetRead() UniversalRead { + if m != nil { + return m.Read + } + return UniversalRead{} +} + +type QueryReadsByTxRequest struct { + TxHash string `protobuf:"bytes,1,opt,name=tx_hash,json=txHash,proto3" json:"tx_hash,omitempty"` +} + +func (m *QueryReadsByTxRequest) Reset() { *m = QueryReadsByTxRequest{} } +func (m *QueryReadsByTxRequest) String() string { return proto.CompactTextString(m) } +func (*QueryReadsByTxRequest) ProtoMessage() {} +func (*QueryReadsByTxRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_a64b97cfcca36b9d, []int{6} +} +func (m *QueryReadsByTxRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryReadsByTxRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryReadsByTxRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryReadsByTxRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryReadsByTxRequest.Merge(m, src) +} +func (m *QueryReadsByTxRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryReadsByTxRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryReadsByTxRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryReadsByTxRequest proto.InternalMessageInfo + +func (m *QueryReadsByTxRequest) GetTxHash() string { + if m != nil { + return m.TxHash + } + return "" +} + +type QueryReadsByTxResponse struct { + // Every read the transaction requested, settled or not, in request-id order. + Reads []UniversalRead `protobuf:"bytes,1,rep,name=reads,proto3" json:"reads"` +} + +func (m *QueryReadsByTxResponse) Reset() { *m = QueryReadsByTxResponse{} } +func (m *QueryReadsByTxResponse) String() string { return proto.CompactTextString(m) } +func (*QueryReadsByTxResponse) ProtoMessage() {} +func (*QueryReadsByTxResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_a64b97cfcca36b9d, []int{7} +} +func (m *QueryReadsByTxResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryReadsByTxResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryReadsByTxResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryReadsByTxResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryReadsByTxResponse.Merge(m, src) +} +func (m *QueryReadsByTxResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryReadsByTxResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryReadsByTxResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryReadsByTxResponse proto.InternalMessageInfo + +func (m *QueryReadsByTxResponse) GetReads() []UniversalRead { + if m != nil { + return m.Reads + } + return nil +} + +type QueryAllAbortedReadRequestsRequest struct { + Pagination *query.PageRequest `protobuf:"bytes,1,opt,name=pagination,proto3" json:"pagination,omitempty"` +} + +func (m *QueryAllAbortedReadRequestsRequest) Reset() { *m = QueryAllAbortedReadRequestsRequest{} } +func (m *QueryAllAbortedReadRequestsRequest) String() string { return proto.CompactTextString(m) } +func (*QueryAllAbortedReadRequestsRequest) ProtoMessage() {} +func (*QueryAllAbortedReadRequestsRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_a64b97cfcca36b9d, []int{8} +} +func (m *QueryAllAbortedReadRequestsRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryAllAbortedReadRequestsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryAllAbortedReadRequestsRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryAllAbortedReadRequestsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryAllAbortedReadRequestsRequest.Merge(m, src) +} +func (m *QueryAllAbortedReadRequestsRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryAllAbortedReadRequestsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryAllAbortedReadRequestsRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryAllAbortedReadRequestsRequest proto.InternalMessageInfo + +func (m *QueryAllAbortedReadRequestsRequest) GetPagination() *query.PageRequest { + if m != nil { + return m.Pagination + } + return nil +} + +type QueryAllAbortedReadRequestsResponse struct { + // Reads whose expiry call never landed. Each carries error_msg explaining why. + Reads []UniversalRead `protobuf:"bytes,1,rep,name=reads,proto3" json:"reads"` + Pagination *query.PageResponse `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination,omitempty"` +} + +func (m *QueryAllAbortedReadRequestsResponse) Reset() { *m = QueryAllAbortedReadRequestsResponse{} } +func (m *QueryAllAbortedReadRequestsResponse) String() string { return proto.CompactTextString(m) } +func (*QueryAllAbortedReadRequestsResponse) ProtoMessage() {} +func (*QueryAllAbortedReadRequestsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_a64b97cfcca36b9d, []int{9} +} +func (m *QueryAllAbortedReadRequestsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryAllAbortedReadRequestsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryAllAbortedReadRequestsResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryAllAbortedReadRequestsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryAllAbortedReadRequestsResponse.Merge(m, src) +} +func (m *QueryAllAbortedReadRequestsResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryAllAbortedReadRequestsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryAllAbortedReadRequestsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryAllAbortedReadRequestsResponse proto.InternalMessageInfo + +func (m *QueryAllAbortedReadRequestsResponse) GetReads() []UniversalRead { + if m != nil { + return m.Reads + } + return nil +} + +func (m *QueryAllAbortedReadRequestsResponse) GetPagination() *query.PageResponse { + if m != nil { + return m.Pagination + } + return nil +} + +func init() { + proto.RegisterType((*QueryParamsRequest)(nil), "ucallback.v1.QueryParamsRequest") + proto.RegisterType((*QueryParamsResponse)(nil), "ucallback.v1.QueryParamsResponse") + proto.RegisterType((*QueryAllPendingReadRequestsRequest)(nil), "ucallback.v1.QueryAllPendingReadRequestsRequest") + proto.RegisterType((*QueryAllPendingReadRequestsResponse)(nil), "ucallback.v1.QueryAllPendingReadRequestsResponse") + proto.RegisterType((*QueryUniversalReadRequest)(nil), "ucallback.v1.QueryUniversalReadRequest") + proto.RegisterType((*QueryUniversalReadResponse)(nil), "ucallback.v1.QueryUniversalReadResponse") + proto.RegisterType((*QueryReadsByTxRequest)(nil), "ucallback.v1.QueryReadsByTxRequest") + proto.RegisterType((*QueryReadsByTxResponse)(nil), "ucallback.v1.QueryReadsByTxResponse") + proto.RegisterType((*QueryAllAbortedReadRequestsRequest)(nil), "ucallback.v1.QueryAllAbortedReadRequestsRequest") + proto.RegisterType((*QueryAllAbortedReadRequestsResponse)(nil), "ucallback.v1.QueryAllAbortedReadRequestsResponse") +} + +func init() { proto.RegisterFile("ucallback/v1/query.proto", fileDescriptor_a64b97cfcca36b9d) } + +var fileDescriptor_a64b97cfcca36b9d = []byte{ + // 657 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x95, 0xcf, 0x6e, 0xd3, 0x40, + 0x10, 0xc6, 0xe3, 0xd2, 0x06, 0x75, 0x0b, 0x97, 0x25, 0x94, 0x62, 0x8a, 0x29, 0x2e, 0xd0, 0xaa, + 0xb4, 0xde, 0x26, 0x08, 0x90, 0xb8, 0x35, 0x48, 0xfc, 0xb9, 0xa5, 0x01, 0x2e, 0x5c, 0xac, 0x75, + 0xbc, 0xb2, 0xad, 0x3a, 0x5e, 0xd7, 0x6b, 0x47, 0x89, 0xaa, 0x5e, 0xe0, 0x05, 0x90, 0x90, 0x78, + 0x05, 0x24, 0x9e, 0xa4, 0xc7, 0x4a, 0x5c, 0x38, 0x21, 0x94, 0x70, 0xe5, 0x1d, 0x90, 0x77, 0xd7, + 0x6d, 0x1c, 0x1c, 0x17, 0x84, 0x84, 0xb8, 0xad, 0xbc, 0xdf, 0xcc, 0xfc, 0xe6, 0xcb, 0xcc, 0x06, + 0x2c, 0x25, 0x1d, 0xec, 0xfb, 0x16, 0xee, 0xec, 0xa1, 0x5e, 0x1d, 0xed, 0x27, 0x24, 0x1a, 0x18, + 0x61, 0x44, 0x63, 0x0a, 0x2f, 0x9c, 0xdc, 0x18, 0xbd, 0xba, 0x5a, 0x73, 0xa8, 0x43, 0xf9, 0x05, + 0x4a, 0x4f, 0x42, 0xa3, 0x2e, 0x3b, 0x94, 0x3a, 0x3e, 0x41, 0x38, 0xf4, 0x10, 0x0e, 0x02, 0x1a, + 0xe3, 0xd8, 0xa3, 0x01, 0x93, 0xb7, 0x1b, 0x1d, 0xca, 0xba, 0x94, 0x21, 0x0b, 0x33, 0x22, 0x52, + 0xa3, 0x5e, 0xdd, 0x22, 0x31, 0xae, 0xa3, 0x10, 0x3b, 0x5e, 0xc0, 0xc5, 0x52, 0xab, 0xe6, 0x38, + 0x1c, 0x12, 0x10, 0xe6, 0x65, 0x79, 0xf2, 0x8c, 0xf1, 0x20, 0x24, 0xf2, 0x46, 0xaf, 0x01, 0xb8, + 0x9b, 0xe6, 0x6d, 0xe1, 0x08, 0x77, 0x59, 0x9b, 0xec, 0x27, 0x84, 0xc5, 0xfa, 0x63, 0x70, 0x29, + 0xf7, 0x95, 0x85, 0x34, 0x60, 0x04, 0x6e, 0x82, 0x6a, 0xc8, 0xbf, 0x2c, 0x29, 0x2b, 0xca, 0xfa, + 0x42, 0xa3, 0x66, 0x8c, 0x77, 0x68, 0x48, 0xb5, 0xd4, 0xe8, 0x3e, 0xd0, 0x79, 0x92, 0x1d, 0xdf, + 0x6f, 0x91, 0xc0, 0xf6, 0x02, 0xa7, 0x4d, 0xb0, 0x2d, 0x4b, 0x64, 0xa5, 0xe0, 0x13, 0x00, 0x4e, + 0x5b, 0x91, 0x79, 0xef, 0x18, 0xa2, 0x6f, 0x23, 0xed, 0xdb, 0x10, 0x96, 0xca, 0xbe, 0x8d, 0x16, + 0x76, 0x88, 0x8c, 0x6d, 0x8f, 0x45, 0xea, 0x1f, 0x15, 0xb0, 0x5a, 0x5a, 0x4e, 0xf6, 0xf0, 0x10, + 0xcc, 0x45, 0x04, 0xdb, 0x69, 0x0b, 0xe7, 0xd6, 0x17, 0x1a, 0xd7, 0xf2, 0x2d, 0xbc, 0x0a, 0xbc, + 0x1e, 0x89, 0x18, 0xf6, 0xd3, 0xd8, 0xe6, 0xec, 0xd1, 0xd7, 0x1b, 0x95, 0xb6, 0xd0, 0xc3, 0xa7, + 0x39, 0xd0, 0x19, 0x0e, 0xba, 0x76, 0x26, 0xa8, 0xa8, 0x9a, 0x23, 0x7d, 0x04, 0xae, 0x72, 0xd0, + 0x5c, 0xad, 0xcc, 0x8e, 0xeb, 0x00, 0x44, 0xe2, 0x68, 0x7a, 0x36, 0xb7, 0x63, 0xbe, 0x3d, 0x2f, + 0xbf, 0x3c, 0xb7, 0xf5, 0x17, 0x40, 0x2d, 0x8a, 0x95, 0xbd, 0xdd, 0x07, 0xb3, 0x29, 0xab, 0x74, + 0xf1, 0x37, 0x5a, 0xe3, 0x72, 0x7d, 0x1b, 0x5c, 0xe6, 0x49, 0xd3, 0x0b, 0xd6, 0x1c, 0xbc, 0xec, + 0x67, 0x30, 0x57, 0xc0, 0xf9, 0xb8, 0x6f, 0xba, 0x98, 0xb9, 0x92, 0xa4, 0x1a, 0xf7, 0x9f, 0x61, + 0xe6, 0xea, 0xbb, 0x60, 0x71, 0x32, 0xe2, 0x2f, 0xed, 0x1d, 0x9f, 0x96, 0x1d, 0x8b, 0x46, 0x31, + 0xb1, 0xff, 0xd5, 0xb4, 0x14, 0x96, 0xfb, 0x5f, 0xa6, 0xa5, 0xf1, 0x63, 0x0e, 0xcc, 0x71, 0x52, + 0xb8, 0x07, 0xaa, 0x62, 0xc3, 0xe0, 0x4a, 0x1e, 0xe3, 0xd7, 0x05, 0x56, 0x6f, 0x96, 0x28, 0x44, + 0x11, 0x7d, 0xf9, 0xcd, 0xe7, 0xef, 0xef, 0x67, 0x16, 0x61, 0x0d, 0xe5, 0x1e, 0x07, 0xb1, 0xbc, + 0xf0, 0x93, 0x02, 0x16, 0x8b, 0x37, 0x09, 0x6e, 0x17, 0xe4, 0x2e, 0xdd, 0x71, 0xb5, 0xfe, 0x07, + 0x11, 0x92, 0xee, 0x2e, 0xa7, 0xbb, 0x0d, 0x57, 0x27, 0xe8, 0x44, 0x88, 0x99, 0x9a, 0x6c, 0x46, + 0x19, 0xd1, 0x07, 0x05, 0x5c, 0xcc, 0xfd, 0x16, 0x70, 0xad, 0xa0, 0x62, 0xd1, 0xbe, 0xa9, 0xeb, + 0x67, 0x0b, 0x25, 0x51, 0x83, 0x13, 0x6d, 0xc2, 0x8d, 0x3c, 0x51, 0x92, 0x89, 0x39, 0x13, 0x43, + 0x07, 0xa7, 0xeb, 0x7b, 0x98, 0xb9, 0x58, 0x30, 0x61, 0xd3, 0x5c, 0x9c, 0x3e, 0xfb, 0xd3, 0x5c, + 0x2c, 0x19, 0xdf, 0x69, 0x2e, 0x62, 0x11, 0x32, 0xe1, 0xe2, 0x5b, 0x05, 0xcc, 0x9f, 0x2c, 0x34, + 0x5c, 0x2d, 0xa8, 0x36, 0xf9, 0x40, 0xa8, 0xb7, 0xca, 0x45, 0xe5, 0x14, 0xdc, 0x2f, 0xd3, 0x1a, + 0x98, 0x71, 0x1f, 0x1d, 0xc8, 0x77, 0xe6, 0xb0, 0xd9, 0x3a, 0x1a, 0x6a, 0xca, 0xf1, 0x50, 0x53, + 0xbe, 0x0d, 0x35, 0xe5, 0xdd, 0x48, 0xab, 0x1c, 0x8f, 0xb4, 0xca, 0x97, 0x91, 0x56, 0x79, 0xfd, + 0xc0, 0xf1, 0x62, 0x37, 0xb1, 0x8c, 0x0e, 0xed, 0xa2, 0x30, 0x61, 0x6e, 0xc7, 0xc5, 0x5e, 0xc0, + 0x4f, 0x5b, 0xfc, 0xb8, 0x15, 0x50, 0x9b, 0xa0, 0xfe, 0x58, 0x11, 0xfe, 0x47, 0x67, 0x55, 0xf9, + 0x3f, 0xdd, 0xbd, 0x9f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x58, 0x0e, 0x64, 0xcc, 0xa9, 0x07, 0x00, + 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// QueryClient is the client API for Query service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type QueryClient interface { + // Params queries all parameters of the module. + Params(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error) + // AllPendingReadRequests lists read requests still awaiting an observation. + // This is the endpoint universal validators poll. + AllPendingReadRequests(ctx context.Context, in *QueryAllPendingReadRequestsRequest, opts ...grpc.CallOption) (*QueryAllPendingReadRequestsResponse, error) + // UniversalRead returns one read by request id, at any point in its lifecycle. + UniversalRead(ctx context.Context, in *QueryUniversalReadRequest, opts ...grpc.CallOption) (*QueryUniversalReadResponse, error) + // AllAbortedReadRequests lists reads the chain gave up on. These need manual + // intervention: the contract may still hold them as pending and the funder's + // refund is unsettled. + AllAbortedReadRequests(ctx context.Context, in *QueryAllAbortedReadRequestsRequest, opts ...grpc.CallOption) (*QueryAllAbortedReadRequestsResponse, error) + // ReadsByTxHash returns every read requested by one Push transaction. A single + // transaction can emit several ReadRequested logs; this reassembles that batch. + ReadsByTx(ctx context.Context, in *QueryReadsByTxRequest, opts ...grpc.CallOption) (*QueryReadsByTxResponse, error) +} + +type queryClient struct { + cc grpc1.ClientConn +} + +func NewQueryClient(cc grpc1.ClientConn) QueryClient { + return &queryClient{cc} +} + +func (c *queryClient) Params(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error) { + out := new(QueryParamsResponse) + err := c.cc.Invoke(ctx, "/ucallback.v1.Query/Params", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) AllPendingReadRequests(ctx context.Context, in *QueryAllPendingReadRequestsRequest, opts ...grpc.CallOption) (*QueryAllPendingReadRequestsResponse, error) { + out := new(QueryAllPendingReadRequestsResponse) + err := c.cc.Invoke(ctx, "/ucallback.v1.Query/AllPendingReadRequests", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) UniversalRead(ctx context.Context, in *QueryUniversalReadRequest, opts ...grpc.CallOption) (*QueryUniversalReadResponse, error) { + out := new(QueryUniversalReadResponse) + err := c.cc.Invoke(ctx, "/ucallback.v1.Query/UniversalRead", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) AllAbortedReadRequests(ctx context.Context, in *QueryAllAbortedReadRequestsRequest, opts ...grpc.CallOption) (*QueryAllAbortedReadRequestsResponse, error) { + out := new(QueryAllAbortedReadRequestsResponse) + err := c.cc.Invoke(ctx, "/ucallback.v1.Query/AllAbortedReadRequests", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) ReadsByTx(ctx context.Context, in *QueryReadsByTxRequest, opts ...grpc.CallOption) (*QueryReadsByTxResponse, error) { + out := new(QueryReadsByTxResponse) + err := c.cc.Invoke(ctx, "/ucallback.v1.Query/ReadsByTx", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// QueryServer is the server API for Query service. +type QueryServer interface { + // Params queries all parameters of the module. + Params(context.Context, *QueryParamsRequest) (*QueryParamsResponse, error) + // AllPendingReadRequests lists read requests still awaiting an observation. + // This is the endpoint universal validators poll. + AllPendingReadRequests(context.Context, *QueryAllPendingReadRequestsRequest) (*QueryAllPendingReadRequestsResponse, error) + // UniversalRead returns one read by request id, at any point in its lifecycle. + UniversalRead(context.Context, *QueryUniversalReadRequest) (*QueryUniversalReadResponse, error) + // AllAbortedReadRequests lists reads the chain gave up on. These need manual + // intervention: the contract may still hold them as pending and the funder's + // refund is unsettled. + AllAbortedReadRequests(context.Context, *QueryAllAbortedReadRequestsRequest) (*QueryAllAbortedReadRequestsResponse, error) + // ReadsByTxHash returns every read requested by one Push transaction. A single + // transaction can emit several ReadRequested logs; this reassembles that batch. + ReadsByTx(context.Context, *QueryReadsByTxRequest) (*QueryReadsByTxResponse, error) +} + +// UnimplementedQueryServer can be embedded to have forward compatible implementations. +type UnimplementedQueryServer struct { +} + +func (*UnimplementedQueryServer) Params(ctx context.Context, req *QueryParamsRequest) (*QueryParamsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Params not implemented") +} +func (*UnimplementedQueryServer) AllPendingReadRequests(ctx context.Context, req *QueryAllPendingReadRequestsRequest) (*QueryAllPendingReadRequestsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method AllPendingReadRequests not implemented") +} +func (*UnimplementedQueryServer) UniversalRead(ctx context.Context, req *QueryUniversalReadRequest) (*QueryUniversalReadResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method UniversalRead not implemented") +} +func (*UnimplementedQueryServer) AllAbortedReadRequests(ctx context.Context, req *QueryAllAbortedReadRequestsRequest) (*QueryAllAbortedReadRequestsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method AllAbortedReadRequests not implemented") +} +func (*UnimplementedQueryServer) ReadsByTx(ctx context.Context, req *QueryReadsByTxRequest) (*QueryReadsByTxResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ReadsByTx not implemented") +} + +func RegisterQueryServer(s grpc1.Server, srv QueryServer) { + s.RegisterService(&_Query_serviceDesc, srv) +} + +func _Query_Params_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryParamsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).Params(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ucallback.v1.Query/Params", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).Params(ctx, req.(*QueryParamsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_AllPendingReadRequests_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryAllPendingReadRequestsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).AllPendingReadRequests(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ucallback.v1.Query/AllPendingReadRequests", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).AllPendingReadRequests(ctx, req.(*QueryAllPendingReadRequestsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_UniversalRead_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryUniversalReadRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).UniversalRead(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ucallback.v1.Query/UniversalRead", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).UniversalRead(ctx, req.(*QueryUniversalReadRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_AllAbortedReadRequests_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryAllAbortedReadRequestsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).AllAbortedReadRequests(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ucallback.v1.Query/AllAbortedReadRequests", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).AllAbortedReadRequests(ctx, req.(*QueryAllAbortedReadRequestsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_ReadsByTx_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryReadsByTxRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).ReadsByTx(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ucallback.v1.Query/ReadsByTx", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).ReadsByTx(ctx, req.(*QueryReadsByTxRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _Query_serviceDesc = grpc.ServiceDesc{ + ServiceName: "ucallback.v1.Query", + HandlerType: (*QueryServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Params", + Handler: _Query_Params_Handler, + }, + { + MethodName: "AllPendingReadRequests", + Handler: _Query_AllPendingReadRequests_Handler, + }, + { + MethodName: "UniversalRead", + Handler: _Query_UniversalRead_Handler, + }, + { + MethodName: "AllAbortedReadRequests", + Handler: _Query_AllAbortedReadRequests_Handler, + }, + { + MethodName: "ReadsByTx", + Handler: _Query_ReadsByTx_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "ucallback/v1/query.proto", +} + +func (m *QueryParamsRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryParamsRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryParamsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *QueryParamsResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryParamsResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryParamsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Params != nil { + { + size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryAllPendingReadRequestsRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryAllPendingReadRequestsRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryAllPendingReadRequestsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Pagination != nil { + { + size, err := m.Pagination.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryAllPendingReadRequestsResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryAllPendingReadRequestsResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryAllPendingReadRequestsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Pagination != nil { + { + size, err := m.Pagination.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if len(m.Reads) > 0 { + for iNdEx := len(m.Reads) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Reads[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *QueryUniversalReadRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryUniversalReadRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryUniversalReadRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.RequestId) > 0 { + i -= len(m.RequestId) + copy(dAtA[i:], m.RequestId) + i = encodeVarintQuery(dAtA, i, uint64(len(m.RequestId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryUniversalReadResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryUniversalReadResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryUniversalReadResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Read.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *QueryReadsByTxRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryReadsByTxRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryReadsByTxRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.TxHash) > 0 { + i -= len(m.TxHash) + copy(dAtA[i:], m.TxHash) + i = encodeVarintQuery(dAtA, i, uint64(len(m.TxHash))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryReadsByTxResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryReadsByTxResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryReadsByTxResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Reads) > 0 { + for iNdEx := len(m.Reads) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Reads[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *QueryAllAbortedReadRequestsRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryAllAbortedReadRequestsRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryAllAbortedReadRequestsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Pagination != nil { + { + size, err := m.Pagination.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryAllAbortedReadRequestsResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryAllAbortedReadRequestsResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryAllAbortedReadRequestsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Pagination != nil { + { + size, err := m.Pagination.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if len(m.Reads) > 0 { + for iNdEx := len(m.Reads) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Reads[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func encodeVarintQuery(dAtA []byte, offset int, v uint64) int { + offset -= sovQuery(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *QueryParamsRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *QueryParamsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Params != nil { + l = m.Params.Size() + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryAllPendingReadRequestsRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Pagination != nil { + l = m.Pagination.Size() + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryAllPendingReadRequestsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Reads) > 0 { + for _, e := range m.Reads { + l = e.Size() + n += 1 + l + sovQuery(uint64(l)) + } + } + if m.Pagination != nil { + l = m.Pagination.Size() + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryUniversalReadRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.RequestId) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryUniversalReadResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Read.Size() + n += 1 + l + sovQuery(uint64(l)) + return n +} + +func (m *QueryReadsByTxRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.TxHash) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryReadsByTxResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Reads) > 0 { + for _, e := range m.Reads { + l = e.Size() + n += 1 + l + sovQuery(uint64(l)) + } + } + return n +} + +func (m *QueryAllAbortedReadRequestsRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Pagination != nil { + l = m.Pagination.Size() + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryAllAbortedReadRequestsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Reads) > 0 { + for _, e := range m.Reads { + l = e.Size() + n += 1 + l + sovQuery(uint64(l)) + } + } + if m.Pagination != nil { + l = m.Pagination.Size() + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func sovQuery(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozQuery(x uint64) (n int) { + return sovQuery(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *QueryParamsRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryParamsRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryParamsRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryParamsResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryParamsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryParamsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Params", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Params == nil { + m.Params = &Params{} + } + if err := m.Params.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryAllPendingReadRequestsRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryAllPendingReadRequestsRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryAllPendingReadRequestsRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pagination", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Pagination == nil { + m.Pagination = &query.PageRequest{} + } + if err := m.Pagination.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryAllPendingReadRequestsResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryAllPendingReadRequestsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryAllPendingReadRequestsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Reads", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Reads = append(m.Reads, UniversalRead{}) + if err := m.Reads[len(m.Reads)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pagination", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Pagination == nil { + m.Pagination = &query.PageResponse{} + } + if err := m.Pagination.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryUniversalReadRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryUniversalReadRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryUniversalReadRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RequestId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.RequestId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryUniversalReadResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryUniversalReadResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryUniversalReadResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Read", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Read.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryReadsByTxRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryReadsByTxRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryReadsByTxRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TxHash", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TxHash = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryReadsByTxResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryReadsByTxResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryReadsByTxResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Reads", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Reads = append(m.Reads, UniversalRead{}) + if err := m.Reads[len(m.Reads)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryAllAbortedReadRequestsRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryAllAbortedReadRequestsRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryAllAbortedReadRequestsRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pagination", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Pagination == nil { + m.Pagination = &query.PageRequest{} + } + if err := m.Pagination.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryAllAbortedReadRequestsResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryAllAbortedReadRequestsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryAllAbortedReadRequestsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Reads", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Reads = append(m.Reads, UniversalRead{}) + if err := m.Reads[len(m.Reads)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pagination", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Pagination == nil { + m.Pagination = &query.PageResponse{} + } + if err := m.Pagination.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipQuery(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthQuery + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupQuery + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthQuery + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthQuery = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowQuery = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupQuery = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/ucallback/types/query.pb.gw.go b/x/ucallback/types/query.pb.gw.go new file mode 100644 index 00000000..1f87e8ec --- /dev/null +++ b/x/ucallback/types/query.pb.gw.go @@ -0,0 +1,521 @@ +// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. +// source: ucallback/v1/query.proto + +/* +Package types is a reverse proxy. + +It translates gRPC into RESTful JSON APIs. +*/ +package types + +import ( + "context" + "io" + "net/http" + + "github.com/golang/protobuf/descriptor" + "github.com/golang/protobuf/proto" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/grpc-ecosystem/grpc-gateway/utilities" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" +) + +// Suppress "imported and not used" errors +var _ codes.Code +var _ io.Reader +var _ status.Status +var _ = runtime.String +var _ = utilities.NewDoubleArray +var _ = descriptor.ForMessage +var _ = metadata.Join + +func request_Query_Params_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryParamsRequest + var metadata runtime.ServerMetadata + + msg, err := client.Params(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_Params_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryParamsRequest + var metadata runtime.ServerMetadata + + msg, err := server.Params(ctx, &protoReq) + return msg, metadata, err + +} + +var ( + filter_Query_AllPendingReadRequests_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_Query_AllPendingReadRequests_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryAllPendingReadRequestsRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_AllPendingReadRequests_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.AllPendingReadRequests(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_AllPendingReadRequests_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryAllPendingReadRequestsRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_AllPendingReadRequests_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.AllPendingReadRequests(ctx, &protoReq) + return msg, metadata, err + +} + +func request_Query_UniversalRead_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryUniversalReadRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["request_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "request_id") + } + + protoReq.RequestId, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "request_id", err) + } + + msg, err := client.UniversalRead(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_UniversalRead_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryUniversalReadRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["request_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "request_id") + } + + protoReq.RequestId, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "request_id", err) + } + + msg, err := server.UniversalRead(ctx, &protoReq) + return msg, metadata, err + +} + +var ( + filter_Query_AllAbortedReadRequests_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_Query_AllAbortedReadRequests_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryAllAbortedReadRequestsRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_AllAbortedReadRequests_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.AllAbortedReadRequests(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_AllAbortedReadRequests_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryAllAbortedReadRequestsRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_AllAbortedReadRequests_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.AllAbortedReadRequests(ctx, &protoReq) + return msg, metadata, err + +} + +func request_Query_ReadsByTx_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryReadsByTxRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["tx_hash"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "tx_hash") + } + + protoReq.TxHash, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "tx_hash", err) + } + + msg, err := client.ReadsByTx(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_ReadsByTx_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryReadsByTxRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["tx_hash"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "tx_hash") + } + + protoReq.TxHash, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "tx_hash", err) + } + + msg, err := server.ReadsByTx(ctx, &protoReq) + return msg, metadata, err + +} + +// RegisterQueryHandlerServer registers the http handlers for service Query to "mux". +// UnaryRPC :call QueryServer directly. +// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. +// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterQueryHandlerFromEndpoint instead. +func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, server QueryServer) error { + + mux.Handle("GET", pattern_Query_Params_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_Params_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_Params_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_AllPendingReadRequests_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_AllPendingReadRequests_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_AllPendingReadRequests_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_UniversalRead_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_UniversalRead_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_UniversalRead_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_AllAbortedReadRequests_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_AllAbortedReadRequests_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_AllAbortedReadRequests_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_ReadsByTx_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_ReadsByTx_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_ReadsByTx_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +// RegisterQueryHandlerFromEndpoint is same as RegisterQueryHandler but +// automatically dials to "endpoint" and closes the connection when "ctx" gets done. +func RegisterQueryHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { + conn, err := grpc.Dial(endpoint, opts...) + if err != nil { + return err + } + defer func() { + if err != nil { + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + return + } + go func() { + <-ctx.Done() + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + }() + }() + + return RegisterQueryHandler(ctx, mux, conn) +} + +// RegisterQueryHandler registers the http handlers for service Query to "mux". +// The handlers forward requests to the grpc endpoint over "conn". +func RegisterQueryHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { + return RegisterQueryHandlerClient(ctx, mux, NewQueryClient(conn)) +} + +// RegisterQueryHandlerClient registers the http handlers for service Query +// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "QueryClient". +// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "QueryClient" +// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in +// "QueryClient" to call the correct interceptors. +func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, client QueryClient) error { + + mux.Handle("GET", pattern_Query_Params_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_Params_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_Params_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_AllPendingReadRequests_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_AllPendingReadRequests_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_AllPendingReadRequests_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_UniversalRead_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_UniversalRead_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_UniversalRead_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_AllAbortedReadRequests_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_AllAbortedReadRequests_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_AllAbortedReadRequests_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_ReadsByTx_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_ReadsByTx_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_ReadsByTx_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +var ( + pattern_Query_Params_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"ucallback", "v1", "params"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_AllPendingReadRequests_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"ucallback", "v1", "pending_read_requests"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_UniversalRead_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"ucallback", "v1", "universal_reads", "request_id"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_AllAbortedReadRequests_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"ucallback", "v1", "aborted_read_requests"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_ReadsByTx_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"ucallback", "v1", "reads_by_tx", "tx_hash"}, "", runtime.AssumeColonVerbOpt(false))) +) + +var ( + forward_Query_Params_0 = runtime.ForwardResponseMessage + + forward_Query_AllPendingReadRequests_0 = runtime.ForwardResponseMessage + + forward_Query_UniversalRead_0 = runtime.ForwardResponseMessage + + forward_Query_AllAbortedReadRequests_0 = runtime.ForwardResponseMessage + + forward_Query_ReadsByTx_0 = runtime.ForwardResponseMessage +) diff --git a/x/ucallback/types/read_event.go b/x/ucallback/types/read_event.go new file mode 100644 index 00000000..a3a25359 --- /dev/null +++ b/x/ucallback/types/read_event.go @@ -0,0 +1,190 @@ +package types + +import ( + "fmt" + "math/big" + "strings" + + evmtypes "github.com/cosmos/evm/x/vm/types" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" +) + +// readRequestedABI is the ABI fragment for UniversalCallback's ReadRequested +// event, transcribed from push-chain-core-contracts: +// +// src/Interfaces/IUniversalCallback.sol — the event +// src/libraries/ReadTypes.sol — ReadSpec +// src/libraries/Types.sol — UniversalAccountId +// +// Held as ABI JSON rather than hand-assembled abi.Type values so that go-ethereum +// derives topic0 for us. A hand-written signature string would be one silent typo +// away from a filter that never matches anything. +// +// Field ORDER is part of the signature, so it is as load-bearing as the types: +// callbackGasLimit sits between originalFunder and totalPaid, not at the end. +// Getting it wrong changes topic0, and IngestReadRequests filters on topic0 — so the +// module drops every real log and records nothing, silently. That is not a +// hypothetical: this fragment had it last until the artifact was checked. +// TestReadRequestedABIMatchesCompiledArtifact pins it. +const readRequestedABI = `[{ + "type": "event", + "name": "ReadRequested", + "anonymous": false, + "inputs": [ + {"name": "requestId", "type": "uint256", "indexed": true}, + {"name": "readSpec", "type": "tuple", "indexed": false, "components": [ + {"name": "account", "type": "tuple", "components": [ + {"name": "chainNamespace", "type": "string"}, + {"name": "chainId", "type": "string"}, + {"name": "owner", "type": "bytes"} + ]}, + {"name": "query", "type": "bytes"}, + {"name": "minConfirmations", "type": "uint16"}, + {"name": "blockNumber", "type": "uint64"}, + {"name": "expiryPushChainHeight", "type": "uint64"}, + {"name": "maxFee", "type": "uint256"}, + {"name": "revertRecipient", "type": "address"} + ]}, + {"name": "callbackTarget", "type": "address", "indexed": true}, + {"name": "originalFunder", "type": "address", "indexed": true}, + {"name": "callbackGasLimit", "type": "uint64", "indexed": false}, + {"name": "totalPaid", "type": "uint256", "indexed": false}, + {"name": "protocolFee", "type": "uint256", "indexed": false}, + {"name": "callbackBudget", "type": "uint256", "indexed": false} + ] +}]` + +var ( + readRequestedEvent abi.Event + // ReadRequestedEventSig is topic0 for ReadRequested, derived from the ABI above. + ReadRequestedEventSig common.Hash +) + +func init() { + parsed, err := abi.JSON(strings.NewReader(readRequestedABI)) + if err != nil { + panic(fmt.Sprintf("ucallback: bad ReadRequested ABI: %v", err)) + } + ev, ok := parsed.Events["ReadRequested"] + if !ok { + panic("ucallback: ReadRequested missing from parsed ABI") + } + readRequestedEvent = ev + ReadRequestedEventSig = ev.ID +} + +// ReadRequestedEvent is a decoded ReadRequested log. +// +// RequestID keeps the raw 32-byte topic hex rather than a decimal string: it is +// handed straight back to the contract as a uint256 on fulfil/expire, and the hex +// form round-trips without a base conversion in the middle. +type ReadRequestedEvent struct { + RequestID string + CallbackTarget string + OriginalFunder string + + ChainNamespace string + ChainID string + Owner []byte + + Query []byte + MinConfirmations uint16 + BlockNumber uint64 + ExpiryPushChainHeight uint64 + MaxFee *big.Int + RevertRecipient string + + // Fee split. ProtocolFee has already left for VaultPC by the time this log is + // emitted; only CallbackBudget is still escrowed on the contract. + TotalPaid *big.Int + ProtocolFee *big.Int + CallbackBudget *big.Int + CallbackGasLimit uint64 +} + +// DestinationChain returns the CAIP-2 identifier the event's account refers to, +// e.g. "eip155:11155111". The contract emits namespace and id separately; every +// other module keys chains by the joined form. +func (e *ReadRequestedEvent) DestinationChain() string { + return e.ChainNamespace + ":" + e.ChainID +} + +// unpackTarget mirrors the non-indexed argument layout of ReadRequested. Field +// order and types must match the ABI above exactly; go-ethereum maps by position +// within each tuple, not by name. +type unpackTarget struct { + ReadSpec struct { + Account struct { + ChainNamespace string + ChainId string + Owner []byte + } + Query []byte + MinConfirmations uint16 + BlockNumber uint64 + ExpiryPushChainHeight uint64 + MaxFee *big.Int + RevertRecipient common.Address + } + TotalPaid *big.Int + ProtocolFee *big.Int + CallbackBudget *big.Int + CallbackGasLimit uint64 +} + +// DecodeReadRequestedFromLog decodes a ReadRequested log. +// +// The caller is responsible for having checked log.Address — this function only +// validates the topic layout, so on its own it would happily decode a forged event +// from an arbitrary contract. +func DecodeReadRequestedFromLog(log *evmtypes.Log) (*ReadRequestedEvent, error) { + if log == nil { + return nil, fmt.Errorf("nil log") + } + if len(log.Topics) != 4 { + return nil, fmt.Errorf("ReadRequested expects 4 topics, got %d", len(log.Topics)) + } + if !strings.EqualFold(log.Topics[0], ReadRequestedEventSig.Hex()) { + return nil, fmt.Errorf("not a ReadRequested event") + } + + var out unpackTarget + values, err := readRequestedEvent.Inputs.NonIndexed().Unpack(log.Data) + if err != nil { + return nil, fmt.Errorf("failed to unpack ReadRequested: %w", err) + } + if err := readRequestedEvent.Inputs.NonIndexed().Copy(&out, values); err != nil { + return nil, fmt.Errorf("failed to map ReadRequested fields: %w", err) + } + + return &ReadRequestedEvent{ + RequestID: strings.ToLower(log.Topics[1]), + CallbackTarget: common.HexToAddress(log.Topics[2]).Hex(), + OriginalFunder: common.HexToAddress(log.Topics[3]).Hex(), + + ChainNamespace: out.ReadSpec.Account.ChainNamespace, + ChainID: out.ReadSpec.Account.ChainId, + Owner: out.ReadSpec.Account.Owner, + + Query: out.ReadSpec.Query, + MinConfirmations: out.ReadSpec.MinConfirmations, + BlockNumber: out.ReadSpec.BlockNumber, + ExpiryPushChainHeight: out.ReadSpec.ExpiryPushChainHeight, + MaxFee: out.ReadSpec.MaxFee, + RevertRecipient: out.ReadSpec.RevertRecipient.Hex(), + + TotalPaid: out.TotalPaid, + ProtocolFee: out.ProtocolFee, + CallbackBudget: out.CallbackBudget, + CallbackGasLimit: out.CallbackGasLimit, + }, nil +} + +// ReadRequestedEventInputs exposes the parsed event inputs so a test can compare +// them against the compiled contract field by field. +func ReadRequestedEventInputs() abi.Arguments { return readRequestedEvent.Inputs } + +// ReadRequestedEventSigName is the human-readable signature topic0 is derived from, +// for error messages that need to show what we expected. +func ReadRequestedEventSigName() string { return readRequestedEvent.Sig } diff --git a/x/ucallback/types/read_event_artifact_test.go b/x/ucallback/types/read_event_artifact_test.go new file mode 100644 index 00000000..3c0ccd99 --- /dev/null +++ b/x/ucallback/types/read_event_artifact_test.go @@ -0,0 +1,55 @@ +package types_test + +import ( + "os" + "strings" + "testing" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/stretchr/testify/require" + + "github.com/pushchain/push-chain-node/x/ucallback/types" +) + +// testdata/read_requested_abi.json is the ReadRequested fragment lifted verbatim +// from the compiled UniversalCallback artifact. +// +// repo: push-chain-core-contracts +// +// Refresh it with `forge build --contracts src/UniversalCallback.sol` and copy the +// ReadRequested entry out of out/UniversalCallback.sol/UniversalCallback.json. +const artifactABIPath = "testdata/read_requested_abi.json" + +// Our ABI fragment is transcribed by hand, and every part of it feeds topic0 — +// types, indexed flags, and field order alike. IngestReadRequests filters on topic0, +// so any drift makes the module silently ignore every real ReadRequested log and +// record nothing at all. No round-trip test catches that: it encodes and decodes +// with the same fragment, so a wrong fragment agrees with itself. +// +// This is the only test that compares us against the contract. It earned its place — +// the fragment had callbackGasLimit last, while the contract emits it fifth. +func TestReadRequestedABIMatchesCompiledArtifact(t *testing.T) { + raw, err := os.ReadFile(artifactABIPath) + require.NoError(t, err, "vendored artifact fragment must be present") + + fromArtifact, err := abi.JSON(strings.NewReader(string(raw))) + require.NoError(t, err) + want, ok := fromArtifact.Events["ReadRequested"] + require.True(t, ok, "artifact must declare ReadRequested") + + require.Equal(t, want.ID, types.ReadRequestedEventSig, + "topic0 disagrees with the compiled contract: %s\n"+ + "ours wants: %s\n"+ + "IngestReadRequests filters on this, so every real log would be dropped", + want.Sig, types.ReadRequestedEventSigName()) + + // topic0 equality already implies the signature matches, but compare the fields + // individually so a failure says which one moved rather than just "hashes differ". + got := types.ReadRequestedEventInputs() + require.Len(t, got, len(want.Inputs), "input count") + for i := range want.Inputs { + require.Equal(t, want.Inputs[i].Name, got[i].Name, "input %d name", i) + require.Equal(t, want.Inputs[i].Type.String(), got[i].Type.String(), "input %d type", i) + require.Equal(t, want.Inputs[i].Indexed, got[i].Indexed, "input %d indexed", i) + } +} diff --git a/x/ucallback/types/read_event_test.go b/x/ucallback/types/read_event_test.go new file mode 100644 index 00000000..61978ff9 --- /dev/null +++ b/x/ucallback/types/read_event_test.go @@ -0,0 +1,176 @@ +package types_test + +import ( + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" + + evmtypes "github.com/cosmos/evm/x/vm/types" + + "github.com/pushchain/push-chain-node/x/ucallback/types" +) + +// readSpec mirrors the contract's ReadSpec for encoding test fixtures. +type account struct { + ChainNamespace string + ChainId string + Owner []byte +} + +type readSpec struct { + Account account + Query []byte + MinConfirmations uint16 + BlockNumber uint64 + ExpiryPushChainHeight uint64 + MaxFee *big.Int + RevertRecipient common.Address +} + +func encodeLog(t *testing.T, spec readSpec, fees *big.Int, requestID, target, funder string) *evmtypes.Log { + t.Helper() + // totalPaid = protocolFee + callbackBudget; the split mirrors the contract. + protocolFee := new(big.Int).Div(fees, big.NewInt(2)) + budget := new(big.Int).Sub(fees, protocolFee) + data, err := types.ReadRequestedEventInputs().NonIndexed(). + Pack(spec, uint64(250_000), fees, protocolFee, budget) + require.NoError(t, err) + + return &evmtypes.Log{ + Address: "0x00000000000000000000000000000000000000C2", + Topics: []string{ + types.ReadRequestedEventSig.Hex(), + requestID, + common.HexToHash(target).Hex(), + common.HexToHash(funder).Hex(), + }, + Data: data, + } +} + +func sampleSpec() readSpec { + return readSpec{ + Account: account{ + ChainNamespace: "eip155", + ChainId: "11155111", + Owner: common.FromHex("0x1111111111111111111111111111111111111111"), + }, + Query: common.FromHex("0xdeadbeef"), + MinConfirmations: 12, + BlockNumber: 8_000_123, + ExpiryPushChainHeight: 900_000, + MaxFee: big.NewInt(5_000_000), + RevertRecipient: common.HexToAddress("0x4444444444444444444444444444444444444444"), + } +} + +// A round-trip through real ABI encoding — if the ABI fragment in read_event.go +// disagrees with the contract's struct layout, this fails. +func TestDecodeReadRequestedFromLog_RoundTrip(t *testing.T) { + spec := sampleSpec() + lg := encodeLog(t, spec, big.NewInt(42_000), + "0x00000000000000000000000000000000000000000000000000000000000000ab", + "0x2222222222222222222222222222222222222222", + "0x3333333333333333333333333333333333333333") + + ev, err := types.DecodeReadRequestedFromLog(lg) + require.NoError(t, err) + + require.Equal(t, "eip155", ev.ChainNamespace) + require.Equal(t, "11155111", ev.ChainID) + require.Equal(t, "eip155:11155111", ev.DestinationChain()) + require.Equal(t, common.FromHex("0x1111111111111111111111111111111111111111"), ev.Owner) + require.Equal(t, common.FromHex("0xdeadbeef"), ev.Query) + require.Equal(t, uint16(12), ev.MinConfirmations) + require.Equal(t, uint64(8_000_123), ev.BlockNumber) + require.Equal(t, uint64(900_000), ev.ExpiryPushChainHeight) + require.Equal(t, big.NewInt(5_000_000), ev.MaxFee) + require.Equal(t, "0x4444444444444444444444444444444444444444", ev.RevertRecipient) + + // the fee split arrives whole, and the two parts must reconstitute the total + require.Equal(t, big.NewInt(42_000), ev.TotalPaid) + require.Equal(t, big.NewInt(21_000), ev.ProtocolFee) + require.Equal(t, big.NewInt(21_000), ev.CallbackBudget) + require.Equal(t, new(big.Int).Add(ev.ProtocolFee, ev.CallbackBudget), ev.TotalPaid) + require.Equal(t, uint64(250_000), ev.CallbackGasLimit) + + require.Equal(t, "0x2222222222222222222222222222222222222222", ev.CallbackTarget) + require.Equal(t, "0x3333333333333333333333333333333333333333", ev.OriginalFunder) + require.Equal(t, + "0x00000000000000000000000000000000000000000000000000000000000000ab", + ev.RequestID, "request id keeps the full 32-byte topic, lowercased") +} + +// expectedReadRequestedTopic0 is keccak of +// +// ReadRequested(uint256,((string,string,bytes),bytes,uint16,uint64,uint64,uint256,address), +// address,address,uint64,uint256,uint256,uint256) +// +// derived independently of the ABI fragment. If the two disagree, one of them has +// drifted from the contract — and a wrong topic0 means ingestion silently matches +// nothing rather than failing. +const expectedReadRequestedTopic0 = "0x4eff8080da7bb648f5eed3bfbb21041b583987e36c6808f5483bd6cf9e160160" + +// topic0 must be derived, never hand-written: a typo would silently produce a +// filter that matches nothing. +func TestReadRequestedEventSig_IsStable(t *testing.T) { + require.Equal(t, + expectedReadRequestedTopic0, + types.ReadRequestedEventSig.Hex(), + "topic0 changed — the contract's event signature moved, or the ABI fragment drifted") +} + +func TestDecodeReadRequestedFromLog_Rejects(t *testing.T) { + spec := sampleSpec() + good := encodeLog(t, spec, big.NewInt(1), + "0x00000000000000000000000000000000000000000000000000000000000000ab", + "0x2222222222222222222222222222222222222222", + "0x3333333333333333333333333333333333333333") + + t.Run("nil log", func(t *testing.T) { + _, err := types.DecodeReadRequestedFromLog(nil) + require.Error(t, err) + }) + + t.Run("wrong topic0", func(t *testing.T) { + bad := *good + bad.Topics = append([]string{}, good.Topics...) + bad.Topics[0] = common.HexToHash("0xdead").Hex() + _, err := types.DecodeReadRequestedFromLog(&bad) + require.Error(t, err) + }) + + t.Run("too few topics", func(t *testing.T) { + bad := *good + bad.Topics = good.Topics[:3] + _, err := types.DecodeReadRequestedFromLog(&bad) + require.Error(t, err) + }) + + t.Run("truncated data", func(t *testing.T) { + bad := *good + bad.Data = good.Data[:len(good.Data)/2] + _, err := types.DecodeReadRequestedFromLog(&bad) + require.Error(t, err) + }) +} + +// Empty owner/query are legitimate on some chains; they must not be an error. +func TestDecodeReadRequestedFromLog_EmptyBytes(t *testing.T) { + spec := sampleSpec() + spec.Account.Owner = []byte{} + spec.Query = []byte{} + spec.MaxFee = big.NewInt(0) + + lg := encodeLog(t, spec, big.NewInt(0), + "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x2222222222222222222222222222222222222222", + "0x3333333333333333333333333333333333333333") + + ev, err := types.DecodeReadRequestedFromLog(lg) + require.NoError(t, err) + require.Empty(t, ev.Owner) + require.Empty(t, ev.Query) +} diff --git a/x/ucallback/types/testdata/read_requested_abi.json b/x/ucallback/types/testdata/read_requested_abi.json new file mode 100644 index 00000000..e381bf3c --- /dev/null +++ b/x/ucallback/types/testdata/read_requested_abi.json @@ -0,0 +1,111 @@ +[ + { + "type": "event", + "name": "ReadRequested", + "inputs": [ + { + "name": "requestId", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + }, + { + "name": "readSpec", + "type": "tuple", + "indexed": false, + "internalType": "struct ReadSpec", + "components": [ + { + "name": "account", + "type": "tuple", + "internalType": "struct UniversalAccountId", + "components": [ + { + "name": "chainNamespace", + "type": "string", + "internalType": "string" + }, + { + "name": "chainId", + "type": "string", + "internalType": "string" + }, + { + "name": "owner", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "query", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "minConfirmations", + "type": "uint16", + "internalType": "uint16" + }, + { + "name": "blockNumber", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "expiryPushChainHeight", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "maxFee", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "revertRecipient", + "type": "address", + "internalType": "address" + } + ] + }, + { + "name": "callbackTarget", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "originalFunder", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "callbackGasLimit", + "type": "uint64", + "indexed": false, + "internalType": "uint64" + }, + { + "name": "totalPaid", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "protocolFee", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "callbackBudget", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + } +] \ No newline at end of file diff --git a/x/ucallback/types/tx.pb.go b/x/ucallback/types/tx.pb.go new file mode 100644 index 00000000..01a85a36 --- /dev/null +++ b/x/ucallback/types/tx.pb.go @@ -0,0 +1,1544 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: ucallback/v1/tx.proto + +package types + +import ( + context "context" + fmt "fmt" + _ "github.com/cosmos/cosmos-proto" + _ "github.com/cosmos/cosmos-sdk/types/msgservice" + _ "github.com/cosmos/cosmos-sdk/types/tx/amino" + _ "github.com/cosmos/gogoproto/gogoproto" + grpc1 "github.com/cosmos/gogoproto/grpc" + proto "github.com/cosmos/gogoproto/proto" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// MsgUpdateParams is the Msg/UpdateParams request type. +// +// Since: cosmos-sdk 0.47 +type MsgUpdateParams struct { + // authority is the address of the governance account. + Authority string `protobuf:"bytes,1,opt,name=authority,proto3" json:"authority,omitempty"` + // params defines the parameters to update. + // + // NOTE: All parameters must be supplied. + Params Params `protobuf:"bytes,2,opt,name=params,proto3" json:"params"` +} + +func (m *MsgUpdateParams) Reset() { *m = MsgUpdateParams{} } +func (m *MsgUpdateParams) String() string { return proto.CompactTextString(m) } +func (*MsgUpdateParams) ProtoMessage() {} +func (*MsgUpdateParams) Descriptor() ([]byte, []int) { + return fileDescriptor_9cc90e16cf6966ee, []int{0} +} +func (m *MsgUpdateParams) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgUpdateParams) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgUpdateParams.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgUpdateParams) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgUpdateParams.Merge(m, src) +} +func (m *MsgUpdateParams) XXX_Size() int { + return m.Size() +} +func (m *MsgUpdateParams) XXX_DiscardUnknown() { + xxx_messageInfo_MsgUpdateParams.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgUpdateParams proto.InternalMessageInfo + +func (m *MsgUpdateParams) GetAuthority() string { + if m != nil { + return m.Authority + } + return "" +} + +func (m *MsgUpdateParams) GetParams() Params { + if m != nil { + return m.Params + } + return Params{} +} + +// MsgUpdateParamsResponse defines the response structure for executing a +// MsgUpdateParams message. +// +// Since: cosmos-sdk 0.47 +type MsgUpdateParamsResponse struct { +} + +func (m *MsgUpdateParamsResponse) Reset() { *m = MsgUpdateParamsResponse{} } +func (m *MsgUpdateParamsResponse) String() string { return proto.CompactTextString(m) } +func (*MsgUpdateParamsResponse) ProtoMessage() {} +func (*MsgUpdateParamsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_9cc90e16cf6966ee, []int{1} +} +func (m *MsgUpdateParamsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgUpdateParamsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgUpdateParamsResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgUpdateParamsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgUpdateParamsResponse.Merge(m, src) +} +func (m *MsgUpdateParamsResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgUpdateParamsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgUpdateParamsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgUpdateParamsResponse proto.InternalMessageInfo + +// MsgVoteReadResult is broadcast by a universal validator that has executed a +// read request against the destination chain. +// +// The ballot the vote lands on is derived from (request_id, result), so two +// validators reporting the same observation converge on one ballot and any +// disagreement produces a distinct ballot that never reaches quorum. Nothing +// validator-local may appear in `result` for that reason — notably there is no +// error message field. +type MsgVoteReadResult struct { + // signer is the Cosmos address of the voting universal validator. + Signer string `protobuf:"bytes,1,opt,name=signer,proto3" json:"signer,omitempty"` + // request_id identifies the read request being voted on. + RequestId string `protobuf:"bytes,2,opt,name=request_id,json=requestId,proto3" json:"request_id,omitempty"` + // result is the observation. Every field participates in the ballot key. + Result *ReadResult `protobuf:"bytes,3,opt,name=result,proto3" json:"result,omitempty"` +} + +func (m *MsgVoteReadResult) Reset() { *m = MsgVoteReadResult{} } +func (m *MsgVoteReadResult) String() string { return proto.CompactTextString(m) } +func (*MsgVoteReadResult) ProtoMessage() {} +func (*MsgVoteReadResult) Descriptor() ([]byte, []int) { + return fileDescriptor_9cc90e16cf6966ee, []int{2} +} +func (m *MsgVoteReadResult) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgVoteReadResult) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgVoteReadResult.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgVoteReadResult) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgVoteReadResult.Merge(m, src) +} +func (m *MsgVoteReadResult) XXX_Size() int { + return m.Size() +} +func (m *MsgVoteReadResult) XXX_DiscardUnknown() { + xxx_messageInfo_MsgVoteReadResult.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgVoteReadResult proto.InternalMessageInfo + +func (m *MsgVoteReadResult) GetSigner() string { + if m != nil { + return m.Signer + } + return "" +} + +func (m *MsgVoteReadResult) GetRequestId() string { + if m != nil { + return m.RequestId + } + return "" +} + +func (m *MsgVoteReadResult) GetResult() *ReadResult { + if m != nil { + return m.Result + } + return nil +} + +type MsgVoteReadResultResponse struct { + // finalized reports whether this vote carried the ballot to quorum. + Finalized bool `protobuf:"varint,1,opt,name=finalized,proto3" json:"finalized,omitempty"` +} + +func (m *MsgVoteReadResultResponse) Reset() { *m = MsgVoteReadResultResponse{} } +func (m *MsgVoteReadResultResponse) String() string { return proto.CompactTextString(m) } +func (*MsgVoteReadResultResponse) ProtoMessage() {} +func (*MsgVoteReadResultResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_9cc90e16cf6966ee, []int{3} +} +func (m *MsgVoteReadResultResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgVoteReadResultResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgVoteReadResultResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgVoteReadResultResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgVoteReadResultResponse.Merge(m, src) +} +func (m *MsgVoteReadResultResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgVoteReadResultResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgVoteReadResultResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgVoteReadResultResponse proto.InternalMessageInfo + +func (m *MsgVoteReadResultResponse) GetFinalized() bool { + if m != nil { + return m.Finalized + } + return false +} + +// MsgRetryReadExpiry is an admin escape hatch. For a read left ABORTED after +// MaxExpiryAttempts, this makes one more attempt at expireExternalRead. +// +// Needed because ABORTED is a dead end that nothing else can leave. The contract +// may still hold the request as pending with the funder's refund uncredited, and +// expireExternalRead is module-gated — no user, relayer or admin can call it +// directly. The sweeper will not retry either: ABORTED is terminal, so the record +// is out of PendingByExpiry. +// +// Each message is worth exactly one attempt: the attempt count is the record's own +// PCTx history, which is already at the limit, so a failure returns it to ABORTED +// with the new reason rather than granting a fresh budget. +type MsgRetryReadExpiry struct { + // signer must equal uvalidator Params.Admin + Signer string `protobuf:"bytes,1,opt,name=signer,proto3" json:"signer,omitempty"` + // request_id of the abandoned read. + RequestId string `protobuf:"bytes,2,opt,name=request_id,json=requestId,proto3" json:"request_id,omitempty"` +} + +func (m *MsgRetryReadExpiry) Reset() { *m = MsgRetryReadExpiry{} } +func (m *MsgRetryReadExpiry) String() string { return proto.CompactTextString(m) } +func (*MsgRetryReadExpiry) ProtoMessage() {} +func (*MsgRetryReadExpiry) Descriptor() ([]byte, []int) { + return fileDescriptor_9cc90e16cf6966ee, []int{4} +} +func (m *MsgRetryReadExpiry) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgRetryReadExpiry) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgRetryReadExpiry.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgRetryReadExpiry) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgRetryReadExpiry.Merge(m, src) +} +func (m *MsgRetryReadExpiry) XXX_Size() int { + return m.Size() +} +func (m *MsgRetryReadExpiry) XXX_DiscardUnknown() { + xxx_messageInfo_MsgRetryReadExpiry.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgRetryReadExpiry proto.InternalMessageInfo + +func (m *MsgRetryReadExpiry) GetSigner() string { + if m != nil { + return m.Signer + } + return "" +} + +func (m *MsgRetryReadExpiry) GetRequestId() string { + if m != nil { + return m.RequestId + } + return "" +} + +type MsgRetryReadExpiryResponse struct { + // settled reports whether the contract accepted the expiry this time. + Settled bool `protobuf:"varint,1,opt,name=settled,proto3" json:"settled,omitempty"` +} + +func (m *MsgRetryReadExpiryResponse) Reset() { *m = MsgRetryReadExpiryResponse{} } +func (m *MsgRetryReadExpiryResponse) String() string { return proto.CompactTextString(m) } +func (*MsgRetryReadExpiryResponse) ProtoMessage() {} +func (*MsgRetryReadExpiryResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_9cc90e16cf6966ee, []int{5} +} +func (m *MsgRetryReadExpiryResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgRetryReadExpiryResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgRetryReadExpiryResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgRetryReadExpiryResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgRetryReadExpiryResponse.Merge(m, src) +} +func (m *MsgRetryReadExpiryResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgRetryReadExpiryResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgRetryReadExpiryResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgRetryReadExpiryResponse proto.InternalMessageInfo + +func (m *MsgRetryReadExpiryResponse) GetSettled() bool { + if m != nil { + return m.Settled + } + return false +} + +func init() { + proto.RegisterType((*MsgUpdateParams)(nil), "ucallback.v1.MsgUpdateParams") + proto.RegisterType((*MsgUpdateParamsResponse)(nil), "ucallback.v1.MsgUpdateParamsResponse") + proto.RegisterType((*MsgVoteReadResult)(nil), "ucallback.v1.MsgVoteReadResult") + proto.RegisterType((*MsgVoteReadResultResponse)(nil), "ucallback.v1.MsgVoteReadResultResponse") + proto.RegisterType((*MsgRetryReadExpiry)(nil), "ucallback.v1.MsgRetryReadExpiry") + proto.RegisterType((*MsgRetryReadExpiryResponse)(nil), "ucallback.v1.MsgRetryReadExpiryResponse") +} + +func init() { proto.RegisterFile("ucallback/v1/tx.proto", fileDescriptor_9cc90e16cf6966ee) } + +var fileDescriptor_9cc90e16cf6966ee = []byte{ + // 547 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x54, 0xcf, 0x8b, 0xd3, 0x40, + 0x14, 0x6e, 0x76, 0x75, 0xb5, 0xe3, 0xb2, 0xcb, 0x86, 0xca, 0xa6, 0x71, 0x37, 0x5b, 0x02, 0x62, + 0xa9, 0xb6, 0x71, 0x2b, 0x14, 0xec, 0xcd, 0x82, 0x07, 0x0f, 0x85, 0x25, 0xfe, 0x38, 0x2c, 0xc8, + 0x92, 0x36, 0xe3, 0x74, 0xb0, 0xc9, 0xc4, 0x79, 0x93, 0xa5, 0xf5, 0x24, 0x1e, 0x05, 0x41, 0xf0, + 0xec, 0xff, 0xd0, 0x83, 0xff, 0x81, 0x97, 0x3d, 0x2e, 0x9e, 0x3c, 0x89, 0xb4, 0x87, 0xfe, 0x1b, + 0xd2, 0x49, 0xda, 0x6c, 0x12, 0xb0, 0x17, 0x2f, 0xe1, 0xcd, 0xf7, 0xbe, 0xf7, 0xbd, 0xf7, 0xbd, + 0x61, 0x82, 0x6e, 0x87, 0x7d, 0x67, 0x38, 0xec, 0x39, 0xfd, 0xb7, 0xd6, 0xf9, 0xb1, 0x25, 0x46, + 0x8d, 0x80, 0x33, 0xc1, 0xd4, 0xed, 0x15, 0xdc, 0x38, 0x3f, 0xd6, 0xf7, 0xfb, 0x0c, 0x3c, 0x06, + 0x96, 0x07, 0x64, 0xc1, 0xf2, 0x80, 0x44, 0x34, 0x5d, 0x4f, 0x55, 0x13, 0xec, 0x63, 0xa0, 0x10, + 0xe7, 0xb4, 0xb4, 0xf2, 0x38, 0xc0, 0xcb, 0x4c, 0x89, 0x30, 0xc2, 0x64, 0x68, 0x2d, 0xa2, 0x18, + 0x2d, 0x47, 0x4d, 0xce, 0xa2, 0x44, 0x74, 0x88, 0x53, 0x7b, 0x8e, 0x47, 0x7d, 0x66, 0xc9, 0x6f, + 0x04, 0x99, 0x9f, 0x15, 0xb4, 0xdb, 0x05, 0xf2, 0x32, 0x70, 0x1d, 0x81, 0x4f, 0x1c, 0xee, 0x78, + 0xa0, 0xb6, 0x50, 0xd1, 0x09, 0xc5, 0x80, 0x71, 0x2a, 0xc6, 0x9a, 0x52, 0x51, 0xaa, 0xc5, 0x8e, + 0xf6, 0xf3, 0x7b, 0xbd, 0x14, 0x6b, 0x3d, 0x71, 0x5d, 0x8e, 0x01, 0x9e, 0x0b, 0x4e, 0x7d, 0x62, + 0x27, 0x54, 0xb5, 0x89, 0xb6, 0x02, 0xa9, 0xa0, 0x6d, 0x54, 0x94, 0xea, 0xad, 0x66, 0xa9, 0x71, + 0xd5, 0x7d, 0x23, 0x52, 0xef, 0x5c, 0xbb, 0xf8, 0x7d, 0x54, 0xb0, 0x63, 0x66, 0x7b, 0xe7, 0xe3, + 0x7c, 0x52, 0x4b, 0x34, 0xcc, 0x32, 0xda, 0xcf, 0x8c, 0x63, 0x63, 0x08, 0x98, 0x0f, 0xd8, 0xfc, + 0xa1, 0xa0, 0xbd, 0x2e, 0x90, 0x57, 0x4c, 0x60, 0x1b, 0x3b, 0xae, 0x8d, 0x21, 0x1c, 0x0a, 0xf5, + 0x21, 0xda, 0x02, 0x4a, 0x7c, 0xcc, 0xd7, 0x4e, 0x1a, 0xf3, 0xd4, 0x43, 0x84, 0x38, 0x7e, 0x17, + 0x62, 0x10, 0x67, 0xd4, 0x95, 0xa3, 0x16, 0xed, 0x62, 0x8c, 0x3c, 0x73, 0x17, 0x82, 0x5c, 0x4a, + 0x6b, 0x9b, 0xd2, 0x85, 0x96, 0x76, 0x91, 0xb4, 0xb6, 0x63, 0x5e, 0xfb, 0xfe, 0xc2, 0x43, 0xac, + 0xfe, 0x69, 0x3e, 0xa9, 0xdd, 0x49, 0x6e, 0x2c, 0x37, 0xaf, 0xf9, 0x18, 0x95, 0x73, 0xe0, 0xd2, + 0xa2, 0x7a, 0x80, 0x8a, 0x6f, 0xa8, 0xef, 0x0c, 0xe9, 0x7b, 0xec, 0x4a, 0x3f, 0x37, 0xed, 0x04, + 0x30, 0xbf, 0x2a, 0x48, 0xed, 0x02, 0xb1, 0xb1, 0xe0, 0xe3, 0x45, 0xf1, 0xd3, 0x51, 0x40, 0xf9, + 0xf8, 0xbf, 0x6f, 0xa0, 0xfd, 0x20, 0xe3, 0xe7, 0x20, 0xe5, 0x27, 0xd3, 0xde, 0x6c, 0x21, 0x3d, + 0x8f, 0xae, 0x1c, 0x69, 0xe8, 0x06, 0x60, 0x21, 0x86, 0x2b, 0x3f, 0xcb, 0x63, 0xf3, 0xdb, 0x06, + 0xda, 0xec, 0x02, 0x51, 0x4f, 0xd1, 0x4e, 0xe6, 0x4a, 0x8f, 0xd2, 0x1b, 0xcf, 0xad, 0x4b, 0xbf, + 0xb7, 0x86, 0xb0, 0xea, 0xfe, 0x1a, 0xed, 0x66, 0xb7, 0x55, 0xc9, 0xd5, 0x66, 0x18, 0x7a, 0x75, + 0x1d, 0x63, 0x25, 0xff, 0x02, 0x6d, 0xa7, 0x1e, 0xce, 0x61, 0xae, 0xf2, 0x6a, 0x5a, 0xbf, 0xfb, + 0xcf, 0xf4, 0x52, 0x55, 0xbf, 0xfe, 0x61, 0x3e, 0xa9, 0x29, 0x9d, 0x93, 0x8b, 0xa9, 0xa1, 0x5c, + 0x4e, 0x0d, 0xe5, 0xcf, 0xd4, 0x50, 0xbe, 0xcc, 0x8c, 0xc2, 0xe5, 0xcc, 0x28, 0xfc, 0x9a, 0x19, + 0x85, 0xd3, 0x16, 0xa1, 0x62, 0x10, 0xf6, 0x1a, 0x7d, 0xe6, 0x59, 0x41, 0x08, 0x83, 0xfe, 0xc0, + 0xa1, 0xbe, 0x8c, 0xea, 0x32, 0xac, 0xfb, 0xcc, 0xc5, 0xd6, 0xc8, 0x4a, 0xae, 0x4d, 0xfe, 0x35, + 0x7a, 0x5b, 0xf2, 0xc9, 0x3f, 0xfa, 0x1b, 0x00, 0x00, 0xff, 0xff, 0x6b, 0xde, 0x55, 0x43, 0xac, + 0x04, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// MsgClient is the client API for Msg service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type MsgClient interface { + // VoteReadResult submits one universal validator's observation of a read + // request's outcome on the destination chain. + VoteReadResult(ctx context.Context, in *MsgVoteReadResult, opts ...grpc.CallOption) (*MsgVoteReadResultResponse, error) + // RetryReadExpiry reopens the expiry of a read the chain abandoned. + RetryReadExpiry(ctx context.Context, in *MsgRetryReadExpiry, opts ...grpc.CallOption) (*MsgRetryReadExpiryResponse, error) + // UpdateParams defines a governance operation for updating the parameters. + // + // Since: cosmos-sdk 0.47 + UpdateParams(ctx context.Context, in *MsgUpdateParams, opts ...grpc.CallOption) (*MsgUpdateParamsResponse, error) +} + +type msgClient struct { + cc grpc1.ClientConn +} + +func NewMsgClient(cc grpc1.ClientConn) MsgClient { + return &msgClient{cc} +} + +func (c *msgClient) VoteReadResult(ctx context.Context, in *MsgVoteReadResult, opts ...grpc.CallOption) (*MsgVoteReadResultResponse, error) { + out := new(MsgVoteReadResultResponse) + err := c.cc.Invoke(ctx, "/ucallback.v1.Msg/VoteReadResult", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) RetryReadExpiry(ctx context.Context, in *MsgRetryReadExpiry, opts ...grpc.CallOption) (*MsgRetryReadExpiryResponse, error) { + out := new(MsgRetryReadExpiryResponse) + err := c.cc.Invoke(ctx, "/ucallback.v1.Msg/RetryReadExpiry", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) UpdateParams(ctx context.Context, in *MsgUpdateParams, opts ...grpc.CallOption) (*MsgUpdateParamsResponse, error) { + out := new(MsgUpdateParamsResponse) + err := c.cc.Invoke(ctx, "/ucallback.v1.Msg/UpdateParams", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// MsgServer is the server API for Msg service. +type MsgServer interface { + // VoteReadResult submits one universal validator's observation of a read + // request's outcome on the destination chain. + VoteReadResult(context.Context, *MsgVoteReadResult) (*MsgVoteReadResultResponse, error) + // RetryReadExpiry reopens the expiry of a read the chain abandoned. + RetryReadExpiry(context.Context, *MsgRetryReadExpiry) (*MsgRetryReadExpiryResponse, error) + // UpdateParams defines a governance operation for updating the parameters. + // + // Since: cosmos-sdk 0.47 + UpdateParams(context.Context, *MsgUpdateParams) (*MsgUpdateParamsResponse, error) +} + +// UnimplementedMsgServer can be embedded to have forward compatible implementations. +type UnimplementedMsgServer struct { +} + +func (*UnimplementedMsgServer) VoteReadResult(ctx context.Context, req *MsgVoteReadResult) (*MsgVoteReadResultResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method VoteReadResult not implemented") +} +func (*UnimplementedMsgServer) RetryReadExpiry(ctx context.Context, req *MsgRetryReadExpiry) (*MsgRetryReadExpiryResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method RetryReadExpiry not implemented") +} +func (*UnimplementedMsgServer) UpdateParams(ctx context.Context, req *MsgUpdateParams) (*MsgUpdateParamsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateParams not implemented") +} + +func RegisterMsgServer(s grpc1.Server, srv MsgServer) { + s.RegisterService(&_Msg_serviceDesc, srv) +} + +func _Msg_VoteReadResult_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgVoteReadResult) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).VoteReadResult(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ucallback.v1.Msg/VoteReadResult", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).VoteReadResult(ctx, req.(*MsgVoteReadResult)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_RetryReadExpiry_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgRetryReadExpiry) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).RetryReadExpiry(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ucallback.v1.Msg/RetryReadExpiry", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).RetryReadExpiry(ctx, req.(*MsgRetryReadExpiry)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_UpdateParams_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgUpdateParams) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).UpdateParams(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ucallback.v1.Msg/UpdateParams", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).UpdateParams(ctx, req.(*MsgUpdateParams)) + } + return interceptor(ctx, in, info, handler) +} + +var _Msg_serviceDesc = grpc.ServiceDesc{ + ServiceName: "ucallback.v1.Msg", + HandlerType: (*MsgServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "VoteReadResult", + Handler: _Msg_VoteReadResult_Handler, + }, + { + MethodName: "RetryReadExpiry", + Handler: _Msg_RetryReadExpiry_Handler, + }, + { + MethodName: "UpdateParams", + Handler: _Msg_UpdateParams_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "ucallback/v1/tx.proto", +} + +func (m *MsgUpdateParams) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgUpdateParams) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgUpdateParams) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if len(m.Authority) > 0 { + i -= len(m.Authority) + copy(dAtA[i:], m.Authority) + i = encodeVarintTx(dAtA, i, uint64(len(m.Authority))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgUpdateParamsResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgUpdateParamsResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgUpdateParamsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *MsgVoteReadResult) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgVoteReadResult) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgVoteReadResult) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Result != nil { + { + size, err := m.Result.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + if len(m.RequestId) > 0 { + i -= len(m.RequestId) + copy(dAtA[i:], m.RequestId) + i = encodeVarintTx(dAtA, i, uint64(len(m.RequestId))) + i-- + dAtA[i] = 0x12 + } + if len(m.Signer) > 0 { + i -= len(m.Signer) + copy(dAtA[i:], m.Signer) + i = encodeVarintTx(dAtA, i, uint64(len(m.Signer))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgVoteReadResultResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgVoteReadResultResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgVoteReadResultResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Finalized { + i-- + if m.Finalized { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *MsgRetryReadExpiry) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgRetryReadExpiry) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgRetryReadExpiry) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.RequestId) > 0 { + i -= len(m.RequestId) + copy(dAtA[i:], m.RequestId) + i = encodeVarintTx(dAtA, i, uint64(len(m.RequestId))) + i-- + dAtA[i] = 0x12 + } + if len(m.Signer) > 0 { + i -= len(m.Signer) + copy(dAtA[i:], m.Signer) + i = encodeVarintTx(dAtA, i, uint64(len(m.Signer))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgRetryReadExpiryResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgRetryReadExpiryResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgRetryReadExpiryResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Settled { + i-- + if m.Settled { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func encodeVarintTx(dAtA []byte, offset int, v uint64) int { + offset -= sovTx(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *MsgUpdateParams) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Authority) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = m.Params.Size() + n += 1 + l + sovTx(uint64(l)) + return n +} + +func (m *MsgUpdateParamsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgVoteReadResult) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Signer) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.RequestId) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if m.Result != nil { + l = m.Result.Size() + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgVoteReadResultResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Finalized { + n += 2 + } + return n +} + +func (m *MsgRetryReadExpiry) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Signer) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.RequestId) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgRetryReadExpiryResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Settled { + n += 2 + } + return n +} + +func sovTx(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozTx(x uint64) (n int) { + return sovTx(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *MsgUpdateParams) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgUpdateParams: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgUpdateParams: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Authority", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Authority = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Params", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Params.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgUpdateParamsResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgUpdateParamsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgUpdateParamsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgVoteReadResult) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgVoteReadResult: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgVoteReadResult: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Signer", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Signer = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RequestId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.RequestId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Result", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Result == nil { + m.Result = &ReadResult{} + } + if err := m.Result.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgVoteReadResultResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgVoteReadResultResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgVoteReadResultResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Finalized", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Finalized = bool(v != 0) + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgRetryReadExpiry) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgRetryReadExpiry: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgRetryReadExpiry: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Signer", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Signer = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RequestId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.RequestId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgRetryReadExpiryResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgRetryReadExpiryResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgRetryReadExpiryResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Settled", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Settled = bool(v != 0) + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipTx(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTx + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTx + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTx + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthTx + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupTx + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthTx + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthTx = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowTx = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupTx = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/ucallback/types/types.pb.go b/x/ucallback/types/types.pb.go new file mode 100644 index 00000000..1a940a67 --- /dev/null +++ b/x/ucallback/types/types.pb.go @@ -0,0 +1,2610 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: ucallback/v1/types.proto + +package types + +import ( + bytes "bytes" + fmt "fmt" + _ "github.com/cosmos/cosmos-sdk/types/tx/amino" + _ "github.com/cosmos/gogoproto/gogoproto" + proto "github.com/cosmos/gogoproto/proto" + types "github.com/pushchain/push-chain-node/x/uexecutor/types" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// ReadStatus is the outcome a universal validator observed for a read. +// ReadErrorCode is the deterministic reason a read produced an ERROR observation. +// Only non-transient failures appear here; transient failures never vote — the +// validator retries locally instead. +type ReadErrorCode int32 + +const ( + ReadErrorCode_READ_ERROR_UNSPECIFIED ReadErrorCode = 0 + ReadErrorCode_READ_ERROR_INVALID_QUERY ReadErrorCode = 1 + ReadErrorCode_READ_ERROR_UNSUPPORTED ReadErrorCode = 2 + ReadErrorCode_READ_ERROR_REVERTED ReadErrorCode = 3 + ReadErrorCode_READ_ERROR_NOT_FOUND ReadErrorCode = 4 + ReadErrorCode_READ_ERROR_INVALID_RESULT ReadErrorCode = 5 + ReadErrorCode_READ_ERROR_REJECTED ReadErrorCode = 6 +) + +var ReadErrorCode_name = map[int32]string{ + 0: "READ_ERROR_UNSPECIFIED", + 1: "READ_ERROR_INVALID_QUERY", + 2: "READ_ERROR_UNSUPPORTED", + 3: "READ_ERROR_REVERTED", + 4: "READ_ERROR_NOT_FOUND", + 5: "READ_ERROR_INVALID_RESULT", + 6: "READ_ERROR_REJECTED", +} + +var ReadErrorCode_value = map[string]int32{ + "READ_ERROR_UNSPECIFIED": 0, + "READ_ERROR_INVALID_QUERY": 1, + "READ_ERROR_UNSUPPORTED": 2, + "READ_ERROR_REVERTED": 3, + "READ_ERROR_NOT_FOUND": 4, + "READ_ERROR_INVALID_RESULT": 5, + "READ_ERROR_REJECTED": 6, +} + +func (x ReadErrorCode) String() string { + return proto.EnumName(ReadErrorCode_name, int32(x)) +} + +func (ReadErrorCode) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_bdb5182bd84a8426, []int{0} +} + +type ReadStatus int32 + +const ( + ReadStatus_READ_STATUS_UNSPECIFIED ReadStatus = 0 + ReadStatus_READ_STATUS_SUCCESS ReadStatus = 1 + ReadStatus_READ_STATUS_ERROR ReadStatus = 2 +) + +var ReadStatus_name = map[int32]string{ + 0: "READ_STATUS_UNSPECIFIED", + 1: "READ_STATUS_SUCCESS", + 2: "READ_STATUS_ERROR", +} + +var ReadStatus_value = map[string]int32{ + "READ_STATUS_UNSPECIFIED": 0, + "READ_STATUS_SUCCESS": 1, + "READ_STATUS_ERROR": 2, +} + +func (x ReadStatus) String() string { + return proto.EnumName(ReadStatus_name, int32(x)) +} + +func (ReadStatus) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_bdb5182bd84a8426, []int{1} +} + +// UniversalReadStatus is the lifecycle state of a read request on Push Chain. +type UniversalReadStatus int32 + +const ( + UniversalReadStatus_UNIVERSAL_READ_STATUS_UNSPECIFIED UniversalReadStatus = 0 + UniversalReadStatus_UNIVERSAL_READ_STATUS_PENDING UniversalReadStatus = 1 + UniversalReadStatus_UNIVERSAL_READ_STATUS_VOTING UniversalReadStatus = 2 + UniversalReadStatus_UNIVERSAL_READ_STATUS_FULFILLED UniversalReadStatus = 3 + UniversalReadStatus_UNIVERSAL_READ_STATUS_EXPIRED UniversalReadStatus = 4 + UniversalReadStatus_UNIVERSAL_READ_STATUS_FAILED UniversalReadStatus = 5 + // Gave up: expireExternalRead failed MaxExpiryAttempts times and the contract + // never acknowledged the request. Distinct from EXPIRED because the contract may + // still hold it as pending — and since expireExternalRead is module-gated, no + // other caller can settle it. Requires manual intervention, the same sense as + // uexecutor's ABORTED. See error_msg on UniversalRead for the last failure. + UniversalReadStatus_UNIVERSAL_READ_STATUS_ABORTED UniversalReadStatus = 6 +) + +var UniversalReadStatus_name = map[int32]string{ + 0: "UNIVERSAL_READ_STATUS_UNSPECIFIED", + 1: "UNIVERSAL_READ_STATUS_PENDING", + 2: "UNIVERSAL_READ_STATUS_VOTING", + 3: "UNIVERSAL_READ_STATUS_FULFILLED", + 4: "UNIVERSAL_READ_STATUS_EXPIRED", + 5: "UNIVERSAL_READ_STATUS_FAILED", + 6: "UNIVERSAL_READ_STATUS_ABORTED", +} + +var UniversalReadStatus_value = map[string]int32{ + "UNIVERSAL_READ_STATUS_UNSPECIFIED": 0, + "UNIVERSAL_READ_STATUS_PENDING": 1, + "UNIVERSAL_READ_STATUS_VOTING": 2, + "UNIVERSAL_READ_STATUS_FULFILLED": 3, + "UNIVERSAL_READ_STATUS_EXPIRED": 4, + "UNIVERSAL_READ_STATUS_FAILED": 5, + "UNIVERSAL_READ_STATUS_ABORTED": 6, +} + +func (x UniversalReadStatus) String() string { + return proto.EnumName(UniversalReadStatus_name, int32(x)) +} + +func (UniversalReadStatus) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_bdb5182bd84a8426, []int{2} +} + +// ReadRequest is one external read requested by an app on Push Chain. +// +// Every field is derived from the UniversalCallback.ReadRequested event, except +// created_at_height / requested_tx_hash / requested_log_index which come from the +// block the log was emitted in. +// +// NOTE: callbackGasLimit is deliberately absent. It is an argument to +// requestExternalReadSelf and is stored in the contract's _pending entry, but it is +// NOT emitted in ReadRequested. It has to be read back via getPendingRead(requestId) +// at fulfilment time, when the gas budget is actually needed. +type ReadRequest struct { + RequestId string `protobuf:"bytes,1,opt,name=request_id,json=requestId,proto3" json:"request_id,omitempty"` + DestinationChain string `protobuf:"bytes,2,opt,name=destination_chain,json=destinationChain,proto3" json:"destination_chain,omitempty"` + Owner []byte `protobuf:"bytes,3,opt,name=owner,proto3" json:"owner,omitempty"` + Query []byte `protobuf:"bytes,4,opt,name=query,proto3" json:"query,omitempty"` + MinConfirmations uint32 `protobuf:"varint,5,opt,name=min_confirmations,json=minConfirmations,proto3" json:"min_confirmations,omitempty"` + DestinationBlockHeight uint64 `protobuf:"varint,6,opt,name=destination_block_height,json=destinationBlockHeight,proto3" json:"destination_block_height,omitempty"` + ExpiryBlockHeight uint64 `protobuf:"varint,7,opt,name=expiry_block_height,json=expiryBlockHeight,proto3" json:"expiry_block_height,omitempty"` + CreatedAtHeight uint64 `protobuf:"varint,8,opt,name=created_at_height,json=createdAtHeight,proto3" json:"created_at_height,omitempty"` + // Bookkeeping — recorded for operators, not consumed by universal validators. + CallbackTarget string `protobuf:"bytes,9,opt,name=callback_target,json=callbackTarget,proto3" json:"callback_target,omitempty"` + OriginalFunder string `protobuf:"bytes,10,opt,name=original_funder,json=originalFunder,proto3" json:"original_funder,omitempty"` + FeesDeposited string `protobuf:"bytes,11,opt,name=fees_deposited,json=feesDeposited,proto3" json:"fees_deposited,omitempty"` + MaxFee string `protobuf:"bytes,12,opt,name=max_fee,json=maxFee,proto3" json:"max_fee,omitempty"` + RequestedTxHash string `protobuf:"bytes,13,opt,name=requested_tx_hash,json=requestedTxHash,proto3" json:"requested_tx_hash,omitempty"` + RequestedLogIndex uint64 `protobuf:"varint,14,opt,name=requested_log_index,json=requestedLogIndex,proto3" json:"requested_log_index,omitempty"` + // Fee split, taken from ReadRequested. protocol_fee is already in VaultPC by the + // time we see the log; only callback_budget is still escrowed on the contract. + ProtocolFee string `protobuf:"bytes,15,opt,name=protocol_fee,json=protocolFee,proto3" json:"protocol_fee,omitempty"` + CallbackBudget string `protobuf:"bytes,16,opt,name=callback_budget,json=callbackBudget,proto3" json:"callback_budget,omitempty"` + // Gas ceiling the app declared for its own callback. The contract caps the inner + // call at this; we size the fulfil transaction from it. + CallbackGasLimit uint64 `protobuf:"varint,17,opt,name=callback_gas_limit,json=callbackGasLimit,proto3" json:"callback_gas_limit,omitempty"` + // Where an unspent budget is refunded. From ReadSpec, not necessarily the funder. + RevertRecipient string `protobuf:"bytes,18,opt,name=revert_recipient,json=revertRecipient,proto3" json:"revert_recipient,omitempty"` +} + +func (m *ReadRequest) Reset() { *m = ReadRequest{} } +func (m *ReadRequest) String() string { return proto.CompactTextString(m) } +func (*ReadRequest) ProtoMessage() {} +func (*ReadRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_bdb5182bd84a8426, []int{0} +} +func (m *ReadRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ReadRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ReadRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ReadRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ReadRequest.Merge(m, src) +} +func (m *ReadRequest) XXX_Size() int { + return m.Size() +} +func (m *ReadRequest) XXX_DiscardUnknown() { + xxx_messageInfo_ReadRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_ReadRequest proto.InternalMessageInfo + +func (m *ReadRequest) GetRequestId() string { + if m != nil { + return m.RequestId + } + return "" +} + +func (m *ReadRequest) GetDestinationChain() string { + if m != nil { + return m.DestinationChain + } + return "" +} + +func (m *ReadRequest) GetOwner() []byte { + if m != nil { + return m.Owner + } + return nil +} + +func (m *ReadRequest) GetQuery() []byte { + if m != nil { + return m.Query + } + return nil +} + +func (m *ReadRequest) GetMinConfirmations() uint32 { + if m != nil { + return m.MinConfirmations + } + return 0 +} + +func (m *ReadRequest) GetDestinationBlockHeight() uint64 { + if m != nil { + return m.DestinationBlockHeight + } + return 0 +} + +func (m *ReadRequest) GetExpiryBlockHeight() uint64 { + if m != nil { + return m.ExpiryBlockHeight + } + return 0 +} + +func (m *ReadRequest) GetCreatedAtHeight() uint64 { + if m != nil { + return m.CreatedAtHeight + } + return 0 +} + +func (m *ReadRequest) GetCallbackTarget() string { + if m != nil { + return m.CallbackTarget + } + return "" +} + +func (m *ReadRequest) GetOriginalFunder() string { + if m != nil { + return m.OriginalFunder + } + return "" +} + +func (m *ReadRequest) GetFeesDeposited() string { + if m != nil { + return m.FeesDeposited + } + return "" +} + +func (m *ReadRequest) GetMaxFee() string { + if m != nil { + return m.MaxFee + } + return "" +} + +func (m *ReadRequest) GetRequestedTxHash() string { + if m != nil { + return m.RequestedTxHash + } + return "" +} + +func (m *ReadRequest) GetRequestedLogIndex() uint64 { + if m != nil { + return m.RequestedLogIndex + } + return 0 +} + +func (m *ReadRequest) GetProtocolFee() string { + if m != nil { + return m.ProtocolFee + } + return "" +} + +func (m *ReadRequest) GetCallbackBudget() string { + if m != nil { + return m.CallbackBudget + } + return "" +} + +func (m *ReadRequest) GetCallbackGasLimit() uint64 { + if m != nil { + return m.CallbackGasLimit + } + return 0 +} + +func (m *ReadRequest) GetRevertRecipient() string { + if m != nil { + return m.RevertRecipient + } + return "" +} + +// ReadResult is the observation a universal validator votes on. +// +// Every field here is covered by the ballot key, so they must be byte-identical +// across validators for a ballot to converge. There is deliberately no error message +// field: local error text differs per node and would prevent agreement. +type ReadResult struct { + Status ReadStatus `protobuf:"varint,1,opt,name=status,proto3,enum=ucallback.v1.ReadStatus" json:"status,omitempty"` + ResultData []byte `protobuf:"bytes,2,opt,name=result_data,json=resultData,proto3" json:"result_data,omitempty"` + // v2 ONLY — always empty in v1. See AggregateValue. + Aggregates []*AggregateValue `protobuf:"bytes,5,rep,name=aggregates,proto3" json:"aggregates,omitempty"` + // Why the read failed. Meaningful only when status is READ_STATUS_ERROR, and + // must be READ_ERROR_UNSPECIFIED otherwise — a SUCCESS vote carrying a code + // would hash to a different ballot than an honest SUCCESS vote and split quorum. + // + // An enum rather than free text on purpose: it participates in the ballot key, + // so it must be a value validators independently converge on. A string invites + // fmt.Sprintf("%v", err), whose text varies by RPC provider even for identical + // on-chain failures. + ErrorCode ReadErrorCode `protobuf:"varint,6,opt,name=error_code,json=errorCode,proto3,enum=ucallback.v1.ReadErrorCode" json:"error_code,omitempty"` +} + +func (m *ReadResult) Reset() { *m = ReadResult{} } +func (m *ReadResult) String() string { return proto.CompactTextString(m) } +func (*ReadResult) ProtoMessage() {} +func (*ReadResult) Descriptor() ([]byte, []int) { + return fileDescriptor_bdb5182bd84a8426, []int{1} +} +func (m *ReadResult) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ReadResult) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ReadResult.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ReadResult) XXX_Merge(src proto.Message) { + xxx_messageInfo_ReadResult.Merge(m, src) +} +func (m *ReadResult) XXX_Size() int { + return m.Size() +} +func (m *ReadResult) XXX_DiscardUnknown() { + xxx_messageInfo_ReadResult.DiscardUnknown(m) +} + +var xxx_messageInfo_ReadResult proto.InternalMessageInfo + +func (m *ReadResult) GetStatus() ReadStatus { + if m != nil { + return m.Status + } + return ReadStatus_READ_STATUS_UNSPECIFIED +} + +func (m *ReadResult) GetResultData() []byte { + if m != nil { + return m.ResultData + } + return nil +} + +func (m *ReadResult) GetAggregates() []*AggregateValue { + if m != nil { + return m.Aggregates + } + return nil +} + +func (m *ReadResult) GetErrorCode() ReadErrorCode { + if m != nil { + return m.ErrorCode + } + return ReadErrorCode_READ_ERROR_UNSPECIFIED +} + +// AggregateValue is one field the module combines across validators instead of +// requiring byte-equality on — a price, say, where honest nodes legitimately differ. +// +// NOT USED IN v1. The universal client rejects any extract mode other than IDENTICAL +// (externalchains/web2/read_envelope.go), so this list is always empty today. The field +// is reserved now because adding it later would change how ballots are keyed on a live +// chain, which is consensus-breaking. In v1 the ballot key covers all of fields 1-4; in +// v2 it must cover only fields 1-4 with `aggregates` EXCLUDED, so computing the key over +// "the identical subset" from the start keeps v2 purely additive. +// +// v2 ALSO REQUIRES REPLACING THE BALLOT MECHANISM, not just populating this field. +// Ballots today store a binary VoteResult{SUCCESS|FAILURE} against an ID that encodes the +// observation, so distinct observations produce distinct ballots and none reaches quorum +// when validators report different numbers. Ballots therefore cannot retain per-validator +// values, which is exactly what a median needs. v2 has to keep each validator's +// AggregateValue set in module state and reduce at quorum — the pattern x/uexecutor +// already uses for gas-price medians in keeper/chain_meta.go, which bypasses ballots for +// the same reason. +type AggregateValue struct { + ExtractIndex uint32 `protobuf:"varint,1,opt,name=extract_index,json=extractIndex,proto3" json:"extract_index,omitempty"` + Mode uint32 `protobuf:"varint,2,opt,name=mode,proto3" json:"mode,omitempty"` + Value []byte `protobuf:"bytes,3,opt,name=value,proto3" json:"value,omitempty"` +} + +func (m *AggregateValue) Reset() { *m = AggregateValue{} } +func (m *AggregateValue) String() string { return proto.CompactTextString(m) } +func (*AggregateValue) ProtoMessage() {} +func (*AggregateValue) Descriptor() ([]byte, []int) { + return fileDescriptor_bdb5182bd84a8426, []int{2} +} +func (m *AggregateValue) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *AggregateValue) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_AggregateValue.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *AggregateValue) XXX_Merge(src proto.Message) { + xxx_messageInfo_AggregateValue.Merge(m, src) +} +func (m *AggregateValue) XXX_Size() int { + return m.Size() +} +func (m *AggregateValue) XXX_DiscardUnknown() { + xxx_messageInfo_AggregateValue.DiscardUnknown(m) +} + +var xxx_messageInfo_AggregateValue proto.InternalMessageInfo + +func (m *AggregateValue) GetExtractIndex() uint32 { + if m != nil { + return m.ExtractIndex + } + return 0 +} + +func (m *AggregateValue) GetMode() uint32 { + if m != nil { + return m.Mode + } + return 0 +} + +func (m *AggregateValue) GetValue() []byte { + if m != nil { + return m.Value + } + return nil +} + +// UniversalRead is the full lifecycle record of one read request. +// +// The read-side sibling of uexecutor's UniversalTx, but deliberately not the same +// shape: a read is triggered by a Push Chain event rather than an external inbound, +// performs no external write, and settles in exactly one Push Chain transaction. +type UniversalRead struct { + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Request *ReadRequest `protobuf:"bytes,2,opt,name=request,proto3" json:"request,omitempty"` + Result *ReadResult `protobuf:"bytes,3,opt,name=result,proto3" json:"result,omitempty"` + Status UniversalReadStatus `protobuf:"varint,4,opt,name=status,proto3,enum=ucallback.v1.UniversalReadStatus" json:"status,omitempty"` + BallotKey string `protobuf:"bytes,5,opt,name=ballot_key,json=ballotKey,proto3" json:"ballot_key,omitempty"` + // Push Chain execution attempts — fulfilExternalCallback and expireExternalRead. + // Repeated because fulfilment can be retried and may be followed by an expiry. + PcTx []*types.PCTx `protobuf:"bytes,6,rep,name=pc_tx,json=pcTx,proto3" json:"pc_tx,omitempty"` + // Why the chain stopped acting on this read. Populated on the ABORTED and FAILED + // paths from the EVM result, so it is identical on every node — this is our own + // execution outcome, not a validator's observation, and it never touches a ballot. + ErrorMsg string `protobuf:"bytes,7,opt,name=error_msg,json=errorMsg,proto3" json:"error_msg,omitempty"` + // How many times the sweeper has called expireExternalRead for this read. + // + // An explicit counter rather than len(pc_tx): pc_tx accumulates every EVM attempt + // on the request, including a failed fulfilment that left it in flight, so + // counting entries would silently shorten the retry budget for exactly the reads + // that already had trouble. + ExpiryAttempts uint32 `protobuf:"varint,8,opt,name=expiry_attempts,json=expiryAttempts,proto3" json:"expiry_attempts,omitempty"` +} + +func (m *UniversalRead) Reset() { *m = UniversalRead{} } +func (m *UniversalRead) String() string { return proto.CompactTextString(m) } +func (*UniversalRead) ProtoMessage() {} +func (*UniversalRead) Descriptor() ([]byte, []int) { + return fileDescriptor_bdb5182bd84a8426, []int{3} +} +func (m *UniversalRead) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *UniversalRead) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_UniversalRead.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *UniversalRead) XXX_Merge(src proto.Message) { + xxx_messageInfo_UniversalRead.Merge(m, src) +} +func (m *UniversalRead) XXX_Size() int { + return m.Size() +} +func (m *UniversalRead) XXX_DiscardUnknown() { + xxx_messageInfo_UniversalRead.DiscardUnknown(m) +} + +var xxx_messageInfo_UniversalRead proto.InternalMessageInfo + +func (m *UniversalRead) GetId() string { + if m != nil { + return m.Id + } + return "" +} + +func (m *UniversalRead) GetRequest() *ReadRequest { + if m != nil { + return m.Request + } + return nil +} + +func (m *UniversalRead) GetResult() *ReadResult { + if m != nil { + return m.Result + } + return nil +} + +func (m *UniversalRead) GetStatus() UniversalReadStatus { + if m != nil { + return m.Status + } + return UniversalReadStatus_UNIVERSAL_READ_STATUS_UNSPECIFIED +} + +func (m *UniversalRead) GetBallotKey() string { + if m != nil { + return m.BallotKey + } + return "" +} + +func (m *UniversalRead) GetPcTx() []*types.PCTx { + if m != nil { + return m.PcTx + } + return nil +} + +func (m *UniversalRead) GetErrorMsg() string { + if m != nil { + return m.ErrorMsg + } + return "" +} + +func (m *UniversalRead) GetExpiryAttempts() uint32 { + if m != nil { + return m.ExpiryAttempts + } + return 0 +} + +func init() { + proto.RegisterEnum("ucallback.v1.ReadErrorCode", ReadErrorCode_name, ReadErrorCode_value) + proto.RegisterEnum("ucallback.v1.ReadStatus", ReadStatus_name, ReadStatus_value) + proto.RegisterEnum("ucallback.v1.UniversalReadStatus", UniversalReadStatus_name, UniversalReadStatus_value) + proto.RegisterType((*ReadRequest)(nil), "ucallback.v1.ReadRequest") + proto.RegisterType((*ReadResult)(nil), "ucallback.v1.ReadResult") + proto.RegisterType((*AggregateValue)(nil), "ucallback.v1.AggregateValue") + proto.RegisterType((*UniversalRead)(nil), "ucallback.v1.UniversalRead") +} + +func init() { proto.RegisterFile("ucallback/v1/types.proto", fileDescriptor_bdb5182bd84a8426) } + +var fileDescriptor_bdb5182bd84a8426 = []byte{ + // 1165 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x56, 0xcf, 0x73, 0xda, 0xc6, + 0x17, 0xb7, 0x30, 0x10, 0xf3, 0x30, 0x58, 0x5e, 0xe7, 0x87, 0xe2, 0xc4, 0xc4, 0x4e, 0x26, 0x13, + 0x7f, 0xfd, 0x6d, 0xa0, 0x71, 0x66, 0x3a, 0x6d, 0xa6, 0x17, 0x0c, 0x22, 0x21, 0xa5, 0x98, 0x2e, + 0xe0, 0x69, 0x7b, 0xd9, 0x59, 0xa4, 0xb5, 0xd0, 0x04, 0x24, 0x22, 0xad, 0x5c, 0xf9, 0x5f, 0xe8, + 0xa9, 0x87, 0xce, 0xf4, 0xda, 0x43, 0x0f, 0x3d, 0xf6, 0xcf, 0xe8, 0x31, 0xc7, 0x1e, 0xdb, 0xf8, + 0xd0, 0x9e, 0xfb, 0x17, 0x74, 0x76, 0x25, 0x11, 0x61, 0xe3, 0x0b, 0xb3, 0xfb, 0xf9, 0x7c, 0xf6, + 0xbd, 0xb7, 0xef, 0xbd, 0x7d, 0x08, 0xb4, 0xc0, 0xa0, 0x93, 0xc9, 0x88, 0x1a, 0x6f, 0x6a, 0x67, + 0xcf, 0x6a, 0xfc, 0x7c, 0xc6, 0xfc, 0xea, 0xcc, 0x73, 0xb9, 0x8b, 0xd6, 0xe7, 0x4c, 0xf5, 0xec, + 0xd9, 0xf6, 0x4d, 0xcb, 0xb5, 0x5c, 0x49, 0xd4, 0xc4, 0x2a, 0xd2, 0x6c, 0x6f, 0xd2, 0xa9, 0xed, + 0xb8, 0x35, 0xf9, 0x1b, 0x43, 0x5a, 0xc0, 0x42, 0x66, 0x04, 0xdc, 0xf5, 0x2e, 0x19, 0x7c, 0xf8, + 0x57, 0x0e, 0x8a, 0x98, 0x51, 0x13, 0xb3, 0xb7, 0x01, 0xf3, 0x39, 0xda, 0x01, 0xf0, 0xa2, 0x25, + 0xb1, 0x4d, 0x4d, 0xd9, 0x55, 0xf6, 0x0b, 0xb8, 0x10, 0x23, 0x6d, 0x13, 0xfd, 0x1f, 0x36, 0x4d, + 0xe6, 0x73, 0xdb, 0xa1, 0xdc, 0x76, 0x1d, 0x62, 0x8c, 0xa9, 0xed, 0x68, 0x19, 0xa9, 0x52, 0x53, + 0x44, 0x43, 0xe0, 0xe8, 0x26, 0xe4, 0xdc, 0xef, 0x1c, 0xe6, 0x69, 0xab, 0xbb, 0xca, 0xfe, 0x3a, + 0x8e, 0x36, 0x02, 0x7d, 0x1b, 0x30, 0xef, 0x5c, 0xcb, 0x46, 0xa8, 0xdc, 0x08, 0xc3, 0x53, 0xdb, + 0x21, 0x86, 0xeb, 0x9c, 0xda, 0xde, 0x54, 0x1a, 0xf1, 0xb5, 0xdc, 0xae, 0xb2, 0x5f, 0xc2, 0xea, + 0xd4, 0x76, 0x1a, 0x69, 0x1c, 0x7d, 0x0a, 0x5a, 0x3a, 0x8a, 0xd1, 0xc4, 0x35, 0xde, 0x90, 0x31, + 0xb3, 0xad, 0x31, 0xd7, 0xf2, 0xbb, 0xca, 0x7e, 0x16, 0xdf, 0x4e, 0xf1, 0x47, 0x82, 0x7e, 0x25, + 0x59, 0x54, 0x85, 0x2d, 0x16, 0xce, 0x6c, 0xef, 0x7c, 0xf1, 0xd0, 0x0d, 0x79, 0x68, 0x33, 0xa2, + 0xd2, 0xfa, 0x03, 0xd8, 0x34, 0x3c, 0x46, 0x39, 0x33, 0x09, 0xe5, 0x89, 0x7a, 0x4d, 0xaa, 0x37, + 0x62, 0xa2, 0xce, 0x63, 0xed, 0x13, 0xd8, 0x48, 0x8a, 0x43, 0x38, 0xf5, 0x2c, 0xc6, 0xb5, 0x82, + 0xcc, 0x4c, 0x39, 0x81, 0x07, 0x12, 0x15, 0x42, 0xd7, 0xb3, 0x2d, 0xdb, 0xa1, 0x13, 0x72, 0x1a, + 0x38, 0x26, 0xf3, 0x34, 0x88, 0x84, 0x09, 0xdc, 0x92, 0x28, 0x7a, 0x0c, 0xe5, 0x53, 0xc6, 0x7c, + 0x62, 0xb2, 0x99, 0xeb, 0xdb, 0x9c, 0x99, 0x5a, 0x51, 0xea, 0x4a, 0x02, 0x6d, 0x26, 0x20, 0xba, + 0x03, 0x37, 0xa6, 0x34, 0x24, 0xa7, 0x8c, 0x69, 0xeb, 0x92, 0xcf, 0x4f, 0x69, 0xd8, 0x62, 0x4c, + 0x44, 0x1f, 0x97, 0x8e, 0x99, 0x84, 0x87, 0x64, 0x4c, 0xfd, 0xb1, 0x56, 0x92, 0x92, 0x8d, 0x39, + 0x31, 0x08, 0x5f, 0x51, 0x7f, 0x2c, 0x32, 0xf3, 0x41, 0x3b, 0x71, 0x2d, 0x62, 0x3b, 0x26, 0x0b, + 0xb5, 0x72, 0x94, 0x99, 0x39, 0xd5, 0x71, 0xad, 0xb6, 0x20, 0xd0, 0x1e, 0xac, 0xcb, 0x0e, 0x32, + 0xdc, 0x89, 0xf4, 0xbc, 0x21, 0xcd, 0x16, 0x13, 0x4c, 0xb8, 0x4f, 0x27, 0x64, 0x14, 0x98, 0x22, + 0x21, 0xea, 0x62, 0x42, 0x8e, 0x24, 0x8a, 0x3e, 0x02, 0x34, 0x17, 0x5a, 0xd4, 0x27, 0x13, 0x7b, + 0x6a, 0x73, 0x6d, 0x53, 0xba, 0x56, 0x13, 0xe6, 0x25, 0xf5, 0x3b, 0x02, 0x47, 0xff, 0x03, 0xd5, + 0x63, 0x67, 0xcc, 0xe3, 0xc4, 0x63, 0x86, 0x3d, 0xb3, 0x99, 0xc3, 0x35, 0x94, 0x5c, 0x4a, 0xe0, + 0x38, 0x81, 0x5f, 0x64, 0xff, 0xf9, 0xf9, 0x81, 0xf2, 0xf0, 0xa7, 0x0c, 0x40, 0xd4, 0xe3, 0x7e, + 0x30, 0xe1, 0xe8, 0x63, 0xc8, 0xfb, 0x9c, 0xf2, 0xc0, 0x97, 0xed, 0x5d, 0x3e, 0xd4, 0xaa, 0xe9, + 0x47, 0x55, 0x15, 0xca, 0xbe, 0xe4, 0x71, 0xac, 0x43, 0x0f, 0xa0, 0xe8, 0xc9, 0xb3, 0xc4, 0xa4, + 0x9c, 0xca, 0x7e, 0x5f, 0xc7, 0x10, 0x41, 0x4d, 0xca, 0x29, 0xfa, 0x1c, 0x80, 0x5a, 0x96, 0xc7, + 0x2c, 0xca, 0x99, 0x68, 0xdb, 0xd5, 0xfd, 0xe2, 0xe1, 0xfd, 0x45, 0xb3, 0xf5, 0x84, 0x3f, 0xa1, + 0x93, 0x80, 0xe1, 0x94, 0x1e, 0xbd, 0x00, 0x60, 0x9e, 0xe7, 0x7a, 0xc4, 0x70, 0x4d, 0x26, 0x1b, + 0xb8, 0x7c, 0x78, 0xef, 0x6a, 0x50, 0xba, 0xd0, 0x34, 0x5c, 0x93, 0xe1, 0x02, 0x4b, 0x96, 0xd1, + 0x0d, 0x5f, 0x67, 0xd7, 0x56, 0xd5, 0xec, 0xeb, 0xec, 0x5a, 0x56, 0xcd, 0xe1, 0x5b, 0xee, 0xc8, + 0x67, 0xde, 0x19, 0x33, 0x17, 0x5a, 0x1c, 0x6f, 0x5d, 0x86, 0xa9, 0x3f, 0x7e, 0xc8, 0xa0, 0xbc, + 0x18, 0x17, 0x7a, 0x04, 0x25, 0x16, 0x72, 0x8f, 0x1a, 0x3c, 0x6e, 0x00, 0x45, 0xbe, 0xc1, 0xf5, + 0x18, 0x8c, 0x6a, 0x8f, 0x20, 0x3b, 0x15, 0xa1, 0x66, 0x24, 0x27, 0xd7, 0xe2, 0x59, 0x9f, 0x09, + 0x0b, 0xc9, 0x63, 0x97, 0x9b, 0xb8, 0x00, 0xff, 0x66, 0xa0, 0x34, 0x74, 0xec, 0x33, 0xe6, 0xf9, + 0x74, 0x22, 0xae, 0x82, 0xca, 0x90, 0x99, 0x8f, 0x97, 0x8c, 0x6d, 0xa2, 0xe7, 0x70, 0x23, 0x6e, + 0x31, 0x69, 0xb4, 0x78, 0x78, 0xf7, 0xea, 0xfd, 0xe3, 0x11, 0x85, 0x13, 0xa5, 0x28, 0x64, 0x54, + 0x03, 0xe9, 0xb3, 0xb8, 0xac, 0x90, 0x51, 0xc9, 0x71, 0xac, 0x43, 0x9f, 0xcd, 0x4b, 0x9f, 0x95, + 0x59, 0xde, 0x5b, 0x3c, 0xb1, 0x10, 0xe3, 0xa5, 0x1e, 0xd8, 0x01, 0x18, 0xd1, 0xc9, 0xc4, 0xe5, + 0xe4, 0x0d, 0x3b, 0x97, 0x93, 0xa9, 0x80, 0x0b, 0x11, 0xf2, 0x05, 0x3b, 0x47, 0x4f, 0x20, 0x37, + 0x33, 0x08, 0x0f, 0xb5, 0xbc, 0x2c, 0x3e, 0xaa, 0xce, 0x27, 0xae, 0x30, 0xdc, 0x6b, 0x0c, 0x42, + 0x9c, 0x9d, 0x19, 0x83, 0x10, 0xdd, 0x83, 0xa8, 0x7a, 0x64, 0xea, 0x5b, 0x72, 0xee, 0x14, 0xf0, + 0x9a, 0x04, 0xbe, 0xf4, 0x2d, 0xf1, 0x62, 0xe2, 0xf1, 0x44, 0x39, 0x67, 0xd3, 0x19, 0xf7, 0xe5, + 0xb0, 0x29, 0xe1, 0x72, 0x04, 0xd7, 0x63, 0xf4, 0xc5, 0x9e, 0xc8, 0xeb, 0xf7, 0x7f, 0xff, 0x76, + 0x90, 0xfa, 0xab, 0x08, 0x92, 0xe8, 0x89, 0xc7, 0xa8, 0x79, 0xf0, 0x4e, 0x81, 0xd2, 0x42, 0xdb, + 0xa0, 0x6d, 0xb8, 0x8d, 0xf5, 0x7a, 0x93, 0xe8, 0x18, 0x1f, 0x63, 0x32, 0xec, 0xf6, 0x7b, 0x7a, + 0xa3, 0xdd, 0x6a, 0xeb, 0x4d, 0x75, 0x05, 0xdd, 0x07, 0x2d, 0xc5, 0xb5, 0xbb, 0x27, 0xf5, 0x4e, + 0xbb, 0x49, 0xbe, 0x1a, 0xea, 0xf8, 0x1b, 0x55, 0xb9, 0x7a, 0x72, 0xd8, 0xeb, 0x1d, 0xe3, 0x81, + 0xde, 0x54, 0x33, 0xe8, 0x0e, 0x6c, 0xa5, 0x38, 0xac, 0x9f, 0xe8, 0x92, 0x58, 0x45, 0x1a, 0xdc, + 0x4c, 0x11, 0xdd, 0xe3, 0x01, 0x69, 0x1d, 0x0f, 0xbb, 0x4d, 0x35, 0x8b, 0x76, 0xe0, 0xee, 0x12, + 0x67, 0x58, 0xef, 0x0f, 0x3b, 0x03, 0x35, 0x77, 0xc5, 0xe2, 0x6b, 0xbd, 0x21, 0x2c, 0xe6, 0x0f, + 0x48, 0xf4, 0x8e, 0xa3, 0xca, 0xa0, 0x7b, 0x70, 0x47, 0xca, 0xfa, 0x83, 0xfa, 0x60, 0xd8, 0xbf, + 0x74, 0x9f, 0xc4, 0x46, 0x4c, 0xf6, 0x87, 0x8d, 0x86, 0xde, 0xef, 0xab, 0x0a, 0xba, 0x05, 0x9b, + 0x69, 0x42, 0xfa, 0x50, 0x33, 0xdb, 0xd9, 0x5f, 0x7f, 0xa9, 0x28, 0x07, 0x3f, 0x66, 0x60, 0x6b, + 0x49, 0x13, 0xa0, 0xc7, 0xb0, 0x37, 0xec, 0xb6, 0x4f, 0x74, 0xdc, 0xaf, 0x77, 0xc8, 0xf5, 0x4e, + 0xf7, 0x60, 0x67, 0xb9, 0xac, 0xa7, 0x77, 0x9b, 0xed, 0xee, 0x4b, 0x55, 0x41, 0xbb, 0x70, 0x7f, + 0xb9, 0xe4, 0xe4, 0x78, 0x20, 0x14, 0x19, 0xf4, 0x08, 0x1e, 0x2c, 0x57, 0xb4, 0x86, 0x9d, 0x56, + 0xbb, 0xd3, 0x91, 0xb9, 0xbd, 0xd6, 0x93, 0xfe, 0x75, 0xaf, 0x8d, 0x75, 0x91, 0xe4, 0x6b, 0x3d, + 0xb5, 0xea, 0x6d, 0x61, 0x24, 0x77, 0xbd, 0x91, 0xfa, 0x51, 0x54, 0xdc, 0x7c, 0x94, 0x96, 0xa3, + 0xde, 0xef, 0xef, 0x2b, 0xca, 0xbb, 0xf7, 0x15, 0xe5, 0xcf, 0xf7, 0x15, 0xe5, 0x87, 0x8b, 0xca, + 0xca, 0xbb, 0x8b, 0xca, 0xca, 0x1f, 0x17, 0x95, 0x95, 0x6f, 0x3f, 0xb1, 0x6c, 0x3e, 0x0e, 0x46, + 0x55, 0xc3, 0x9d, 0xd6, 0x66, 0x81, 0x3f, 0x96, 0x1f, 0x04, 0x72, 0xf5, 0x54, 0x2e, 0x9f, 0x3a, + 0xae, 0xc9, 0x6a, 0x61, 0xed, 0x43, 0x97, 0xca, 0x8f, 0x8f, 0x51, 0x5e, 0xfe, 0x4f, 0x3c, 0xff, + 0x2f, 0x00, 0x00, 0xff, 0xff, 0x5e, 0x66, 0xe0, 0x1c, 0xea, 0x08, 0x00, 0x00, +} + +func (this *ReadRequest) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*ReadRequest) + if !ok { + that2, ok := that.(ReadRequest) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.RequestId != that1.RequestId { + return false + } + if this.DestinationChain != that1.DestinationChain { + return false + } + if !bytes.Equal(this.Owner, that1.Owner) { + return false + } + if !bytes.Equal(this.Query, that1.Query) { + return false + } + if this.MinConfirmations != that1.MinConfirmations { + return false + } + if this.DestinationBlockHeight != that1.DestinationBlockHeight { + return false + } + if this.ExpiryBlockHeight != that1.ExpiryBlockHeight { + return false + } + if this.CreatedAtHeight != that1.CreatedAtHeight { + return false + } + if this.CallbackTarget != that1.CallbackTarget { + return false + } + if this.OriginalFunder != that1.OriginalFunder { + return false + } + if this.FeesDeposited != that1.FeesDeposited { + return false + } + if this.MaxFee != that1.MaxFee { + return false + } + if this.RequestedTxHash != that1.RequestedTxHash { + return false + } + if this.RequestedLogIndex != that1.RequestedLogIndex { + return false + } + if this.ProtocolFee != that1.ProtocolFee { + return false + } + if this.CallbackBudget != that1.CallbackBudget { + return false + } + if this.CallbackGasLimit != that1.CallbackGasLimit { + return false + } + if this.RevertRecipient != that1.RevertRecipient { + return false + } + return true +} +func (this *ReadResult) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*ReadResult) + if !ok { + that2, ok := that.(ReadResult) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.Status != that1.Status { + return false + } + if !bytes.Equal(this.ResultData, that1.ResultData) { + return false + } + if len(this.Aggregates) != len(that1.Aggregates) { + return false + } + for i := range this.Aggregates { + if !this.Aggregates[i].Equal(that1.Aggregates[i]) { + return false + } + } + if this.ErrorCode != that1.ErrorCode { + return false + } + return true +} +func (this *AggregateValue) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*AggregateValue) + if !ok { + that2, ok := that.(AggregateValue) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.ExtractIndex != that1.ExtractIndex { + return false + } + if this.Mode != that1.Mode { + return false + } + if !bytes.Equal(this.Value, that1.Value) { + return false + } + return true +} +func (this *UniversalRead) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*UniversalRead) + if !ok { + that2, ok := that.(UniversalRead) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.Id != that1.Id { + return false + } + if !this.Request.Equal(that1.Request) { + return false + } + if !this.Result.Equal(that1.Result) { + return false + } + if this.Status != that1.Status { + return false + } + if this.BallotKey != that1.BallotKey { + return false + } + if len(this.PcTx) != len(that1.PcTx) { + return false + } + for i := range this.PcTx { + if !this.PcTx[i].Equal(that1.PcTx[i]) { + return false + } + } + if this.ErrorMsg != that1.ErrorMsg { + return false + } + if this.ExpiryAttempts != that1.ExpiryAttempts { + return false + } + return true +} +func (m *ReadRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ReadRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ReadRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.RevertRecipient) > 0 { + i -= len(m.RevertRecipient) + copy(dAtA[i:], m.RevertRecipient) + i = encodeVarintTypes(dAtA, i, uint64(len(m.RevertRecipient))) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0x92 + } + if m.CallbackGasLimit != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.CallbackGasLimit)) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0x88 + } + if len(m.CallbackBudget) > 0 { + i -= len(m.CallbackBudget) + copy(dAtA[i:], m.CallbackBudget) + i = encodeVarintTypes(dAtA, i, uint64(len(m.CallbackBudget))) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0x82 + } + if len(m.ProtocolFee) > 0 { + i -= len(m.ProtocolFee) + copy(dAtA[i:], m.ProtocolFee) + i = encodeVarintTypes(dAtA, i, uint64(len(m.ProtocolFee))) + i-- + dAtA[i] = 0x7a + } + if m.RequestedLogIndex != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.RequestedLogIndex)) + i-- + dAtA[i] = 0x70 + } + if len(m.RequestedTxHash) > 0 { + i -= len(m.RequestedTxHash) + copy(dAtA[i:], m.RequestedTxHash) + i = encodeVarintTypes(dAtA, i, uint64(len(m.RequestedTxHash))) + i-- + dAtA[i] = 0x6a + } + if len(m.MaxFee) > 0 { + i -= len(m.MaxFee) + copy(dAtA[i:], m.MaxFee) + i = encodeVarintTypes(dAtA, i, uint64(len(m.MaxFee))) + i-- + dAtA[i] = 0x62 + } + if len(m.FeesDeposited) > 0 { + i -= len(m.FeesDeposited) + copy(dAtA[i:], m.FeesDeposited) + i = encodeVarintTypes(dAtA, i, uint64(len(m.FeesDeposited))) + i-- + dAtA[i] = 0x5a + } + if len(m.OriginalFunder) > 0 { + i -= len(m.OriginalFunder) + copy(dAtA[i:], m.OriginalFunder) + i = encodeVarintTypes(dAtA, i, uint64(len(m.OriginalFunder))) + i-- + dAtA[i] = 0x52 + } + if len(m.CallbackTarget) > 0 { + i -= len(m.CallbackTarget) + copy(dAtA[i:], m.CallbackTarget) + i = encodeVarintTypes(dAtA, i, uint64(len(m.CallbackTarget))) + i-- + dAtA[i] = 0x4a + } + if m.CreatedAtHeight != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.CreatedAtHeight)) + i-- + dAtA[i] = 0x40 + } + if m.ExpiryBlockHeight != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.ExpiryBlockHeight)) + i-- + dAtA[i] = 0x38 + } + if m.DestinationBlockHeight != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.DestinationBlockHeight)) + i-- + dAtA[i] = 0x30 + } + if m.MinConfirmations != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.MinConfirmations)) + i-- + dAtA[i] = 0x28 + } + if len(m.Query) > 0 { + i -= len(m.Query) + copy(dAtA[i:], m.Query) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Query))) + i-- + dAtA[i] = 0x22 + } + if len(m.Owner) > 0 { + i -= len(m.Owner) + copy(dAtA[i:], m.Owner) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Owner))) + i-- + dAtA[i] = 0x1a + } + if len(m.DestinationChain) > 0 { + i -= len(m.DestinationChain) + copy(dAtA[i:], m.DestinationChain) + i = encodeVarintTypes(dAtA, i, uint64(len(m.DestinationChain))) + i-- + dAtA[i] = 0x12 + } + if len(m.RequestId) > 0 { + i -= len(m.RequestId) + copy(dAtA[i:], m.RequestId) + i = encodeVarintTypes(dAtA, i, uint64(len(m.RequestId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *ReadResult) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ReadResult) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ReadResult) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.ErrorCode != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.ErrorCode)) + i-- + dAtA[i] = 0x30 + } + if len(m.Aggregates) > 0 { + for iNdEx := len(m.Aggregates) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Aggregates[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a + } + } + if len(m.ResultData) > 0 { + i -= len(m.ResultData) + copy(dAtA[i:], m.ResultData) + i = encodeVarintTypes(dAtA, i, uint64(len(m.ResultData))) + i-- + dAtA[i] = 0x12 + } + if m.Status != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.Status)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *AggregateValue) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *AggregateValue) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *AggregateValue) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Value) > 0 { + i -= len(m.Value) + copy(dAtA[i:], m.Value) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Value))) + i-- + dAtA[i] = 0x1a + } + if m.Mode != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.Mode)) + i-- + dAtA[i] = 0x10 + } + if m.ExtractIndex != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.ExtractIndex)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *UniversalRead) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *UniversalRead) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *UniversalRead) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.ExpiryAttempts != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.ExpiryAttempts)) + i-- + dAtA[i] = 0x40 + } + if len(m.ErrorMsg) > 0 { + i -= len(m.ErrorMsg) + copy(dAtA[i:], m.ErrorMsg) + i = encodeVarintTypes(dAtA, i, uint64(len(m.ErrorMsg))) + i-- + dAtA[i] = 0x3a + } + if len(m.PcTx) > 0 { + for iNdEx := len(m.PcTx) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.PcTx[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x32 + } + } + if len(m.BallotKey) > 0 { + i -= len(m.BallotKey) + copy(dAtA[i:], m.BallotKey) + i = encodeVarintTypes(dAtA, i, uint64(len(m.BallotKey))) + i-- + dAtA[i] = 0x2a + } + if m.Status != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.Status)) + i-- + dAtA[i] = 0x20 + } + if m.Result != nil { + { + size, err := m.Result.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + if m.Request != nil { + { + size, err := m.Request.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if len(m.Id) > 0 { + i -= len(m.Id) + copy(dAtA[i:], m.Id) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Id))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintTypes(dAtA []byte, offset int, v uint64) int { + offset -= sovTypes(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *ReadRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.RequestId) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.DestinationChain) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.Owner) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.Query) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + if m.MinConfirmations != 0 { + n += 1 + sovTypes(uint64(m.MinConfirmations)) + } + if m.DestinationBlockHeight != 0 { + n += 1 + sovTypes(uint64(m.DestinationBlockHeight)) + } + if m.ExpiryBlockHeight != 0 { + n += 1 + sovTypes(uint64(m.ExpiryBlockHeight)) + } + if m.CreatedAtHeight != 0 { + n += 1 + sovTypes(uint64(m.CreatedAtHeight)) + } + l = len(m.CallbackTarget) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.OriginalFunder) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.FeesDeposited) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.MaxFee) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.RequestedTxHash) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + if m.RequestedLogIndex != 0 { + n += 1 + sovTypes(uint64(m.RequestedLogIndex)) + } + l = len(m.ProtocolFee) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.CallbackBudget) + if l > 0 { + n += 2 + l + sovTypes(uint64(l)) + } + if m.CallbackGasLimit != 0 { + n += 2 + sovTypes(uint64(m.CallbackGasLimit)) + } + l = len(m.RevertRecipient) + if l > 0 { + n += 2 + l + sovTypes(uint64(l)) + } + return n +} + +func (m *ReadResult) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Status != 0 { + n += 1 + sovTypes(uint64(m.Status)) + } + l = len(m.ResultData) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + if len(m.Aggregates) > 0 { + for _, e := range m.Aggregates { + l = e.Size() + n += 1 + l + sovTypes(uint64(l)) + } + } + if m.ErrorCode != 0 { + n += 1 + sovTypes(uint64(m.ErrorCode)) + } + return n +} + +func (m *AggregateValue) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.ExtractIndex != 0 { + n += 1 + sovTypes(uint64(m.ExtractIndex)) + } + if m.Mode != 0 { + n += 1 + sovTypes(uint64(m.Mode)) + } + l = len(m.Value) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + return n +} + +func (m *UniversalRead) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Id) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + if m.Request != nil { + l = m.Request.Size() + n += 1 + l + sovTypes(uint64(l)) + } + if m.Result != nil { + l = m.Result.Size() + n += 1 + l + sovTypes(uint64(l)) + } + if m.Status != 0 { + n += 1 + sovTypes(uint64(m.Status)) + } + l = len(m.BallotKey) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + if len(m.PcTx) > 0 { + for _, e := range m.PcTx { + l = e.Size() + n += 1 + l + sovTypes(uint64(l)) + } + } + l = len(m.ErrorMsg) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + if m.ExpiryAttempts != 0 { + n += 1 + sovTypes(uint64(m.ExpiryAttempts)) + } + return n +} + +func sovTypes(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozTypes(x uint64) (n int) { + return sovTypes(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *ReadRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ReadRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ReadRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RequestId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.RequestId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DestinationChain", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.DestinationChain = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Owner", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Owner = append(m.Owner[:0], dAtA[iNdEx:postIndex]...) + if m.Owner == nil { + m.Owner = []byte{} + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Query", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Query = append(m.Query[:0], dAtA[iNdEx:postIndex]...) + if m.Query == nil { + m.Query = []byte{} + } + iNdEx = postIndex + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field MinConfirmations", wireType) + } + m.MinConfirmations = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.MinConfirmations |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 6: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field DestinationBlockHeight", wireType) + } + m.DestinationBlockHeight = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.DestinationBlockHeight |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 7: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ExpiryBlockHeight", wireType) + } + m.ExpiryBlockHeight = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ExpiryBlockHeight |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 8: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CreatedAtHeight", wireType) + } + m.CreatedAtHeight = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CreatedAtHeight |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 9: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CallbackTarget", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.CallbackTarget = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 10: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field OriginalFunder", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.OriginalFunder = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 11: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field FeesDeposited", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.FeesDeposited = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 12: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MaxFee", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.MaxFee = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 13: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RequestedTxHash", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.RequestedTxHash = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 14: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field RequestedLogIndex", wireType) + } + m.RequestedLogIndex = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.RequestedLogIndex |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 15: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ProtocolFee", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ProtocolFee = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 16: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CallbackBudget", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.CallbackBudget = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 17: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CallbackGasLimit", wireType) + } + m.CallbackGasLimit = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CallbackGasLimit |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 18: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RevertRecipient", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.RevertRecipient = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ReadResult) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ReadResult: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ReadResult: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Status", wireType) + } + m.Status = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Status |= ReadStatus(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ResultData", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ResultData = append(m.ResultData[:0], dAtA[iNdEx:postIndex]...) + if m.ResultData == nil { + m.ResultData = []byte{} + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Aggregates", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Aggregates = append(m.Aggregates, &AggregateValue{}) + if err := m.Aggregates[len(m.Aggregates)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 6: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ErrorCode", wireType) + } + m.ErrorCode = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ErrorCode |= ReadErrorCode(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *AggregateValue) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: AggregateValue: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AggregateValue: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ExtractIndex", wireType) + } + m.ExtractIndex = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ExtractIndex |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Mode", wireType) + } + m.Mode = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Mode |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Value", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Value = append(m.Value[:0], dAtA[iNdEx:postIndex]...) + if m.Value == nil { + m.Value = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *UniversalRead) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: UniversalRead: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: UniversalRead: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Id", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Id = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Request", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Request == nil { + m.Request = &ReadRequest{} + } + if err := m.Request.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Result", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Result == nil { + m.Result = &ReadResult{} + } + if err := m.Result.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Status", wireType) + } + m.Status = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Status |= UniversalReadStatus(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field BallotKey", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.BallotKey = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PcTx", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.PcTx = append(m.PcTx, &types.PCTx{}) + if err := m.PcTx[len(m.PcTx)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ErrorMsg", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ErrorMsg = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 8: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ExpiryAttempts", wireType) + } + m.ExpiryAttempts = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ExpiryAttempts |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipTypes(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTypes + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTypes + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTypes + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthTypes + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupTypes + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthTypes + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthTypes = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowTypes = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupTypes = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/uregistry/types/constants.go b/x/uregistry/types/constants.go index da0383bc..8915ac4e 100644 --- a/x/uregistry/types/constants.go +++ b/x/uregistry/types/constants.go @@ -51,6 +51,16 @@ var SYSTEM_CONTRACTS = map[string]ContractAddresses{ ProxyAdmin: "0xF2000000000000000000000000000000000000C1", Implementation: "0xF1000000000000000000000000000000000000C1", }, + // UNIVERSAL_CALLBACK is the read-request contract x/ucallback listens to. + // Promoted out of the RESERVED_C2 auto-reservation below: same address, same + // admin, same implementation, and (until the real contract ships) the same + // placeholder bytecode — so genesis state is byte-identical to before the + // rename, and chains that already deployed 0xC2 skip it as already-deployed. + "UNIVERSAL_CALLBACK": { + Address: "0x00000000000000000000000000000000000000C2", + ProxyAdmin: "0xF2000000000000000000000000000000000000C2", + Implementation: "0xF1000000000000000000000000000000000000C2", + }, "VAULT_PC": { Address: "0x00000000000000000000000000000000000000B0", ProxyAdmin: "0xF2000000000000000000000000000000000000b0", @@ -142,7 +152,8 @@ func reservedProxyBytecode(slotByte byte) []byte { // Range policy: // - 0xA0-0xAF: Proxy Admins / low-level modules (0xAA pre-occupied by uexecutor) // - 0xB0-0xBF: Vaults + utility (0xB0 = VAULT_PC; 0xB1 = VAULT_PC20; 0xB2 = RESERVED_2; 0xBC = UNIVERSAL_BATCH_CALL) -// - 0xC0-0xCF: Chain abstraction (0xC0 = UNIVERSAL_CORE; 0xC1 = UNIVERSAL_GATEWAY_PC; 0xCA = USigVerifier legacy precompile) +// - 0xC0-0xCF: Chain abstraction (0xC0 = UNIVERSAL_CORE; 0xC1 = UNIVERSAL_GATEWAY_PC; +// 0xC2 = UNIVERSAL_CALLBACK; 0xCA = USigVerifier legacy precompile) // - 0xD0-0xFF: NOT reserved — left to other chains / future debug use // // Choice of full triples (vs bytecode-only): future activation of a reserved @@ -154,6 +165,16 @@ func init() { 0xB0: true, 0xB1: true, 0xB2: true, // VAULT_PC / VAULT_PC20 / RESERVED_2 0xBC: true, 0xC0: true, 0xC1: true, // UNIVERSAL_CORE, UNIVERSAL_GATEWAY_PC + 0xC2: true, // UNIVERSAL_CALLBACK + } + + // Placeholder bytecode for UNIVERSAL_CALLBACK, identical to what RESERVED_C2 + // carried before the promotion. Replaced with the real compiled contract in + // the commit that deploys it. + BYTECODE["UNIVERSAL_CALLBACK"] = ByteCodes{ + IMPL_RUNTIME: ReservedImplRuntimeBytecode, + PROXY_RUNTIME: reservedProxyBytecode(0xC2), + ADMIN_RUNTIME: ProxyAdminRuntimeBytecode, } for _, hi := range []byte{0xA, 0xB, 0xC} { diff --git a/x/uregistry/types/constants_test.go b/x/uregistry/types/constants_test.go index 70694af0..14fba92b 100644 --- a/x/uregistry/types/constants_test.go +++ b/x/uregistry/types/constants_test.go @@ -21,7 +21,9 @@ func TestReservedSlots_FullTripleDeployedForEveryUnoccupiedABCSlot(t *testing.T) occupied := map[byte]bool{ 0xAA: true, 0xB0: true, 0xB1: true, 0xB2: true, 0xBC: true, - 0xC0: true, 0xC1: true, 0xCA: true, + 0xC0: true, 0xC1: true, + 0xC2: true, // promoted to UNIVERSAL_CALLBACK; covered by the test below + 0xCA: true, // legacy USigVerifier precompile, see usigverifier.go } for _, hi := range []byte{0xA, 0xB, 0xC} { @@ -166,3 +168,40 @@ func TestReservedSlots_BytecodeIsCaseInsensitiveAcrossSlots(t *testing.T) { require.Equal(t, src, upperBytes, "UPPERCASE hex must decode to identical bytes (case-insensitive)") require.Equal(t, src, mixedBytes, "MiXeD hex must decode to identical bytes (case-insensitive)") } + +// TestUniversalCallbackSlot_KeepsReservedTriple asserts that promoting 0xC2 out of +// the RESERVED_* auto-reservation did not weaken it. The slot must still carry a +// complete proxy + admin + impl triple with the same addresses RESERVED_C2 had, so +// the promotion is a rename and genesis state is unchanged. +func TestUniversalCallbackSlot_KeepsReservedTriple(t *testing.T) { + addrs, ok := SYSTEM_CONTRACTS["UNIVERSAL_CALLBACK"] + require.True(t, ok, "UNIVERSAL_CALLBACK missing from SYSTEM_CONTRACTS") + + require.Equal(t, "0x00000000000000000000000000000000000000c2", strings.ToLower(addrs.Address)) + require.Equal(t, "0xf2000000000000000000000000000000000000c2", strings.ToLower(addrs.ProxyAdmin)) + require.Equal(t, "0xf1000000000000000000000000000000000000c2", strings.ToLower(addrs.Implementation)) + + bc, ok := BYTECODE["UNIVERSAL_CALLBACK"] + require.True(t, ok, "BYTECODE missing entry UNIVERSAL_CALLBACK") + require.NotEmpty(t, bc.IMPL_RUNTIME) + require.NotEmpty(t, bc.PROXY_RUNTIME) + require.NotEmpty(t, bc.ADMIN_RUNTIME) + + // the proxy must embed ITS OWN admin, not the 0xB0 template's + require.Contains(t, + strings.ToLower(hex.EncodeToString(bc.PROXY_RUNTIME)), + "f2000000000000000000000000000000000000c2") + + // the old name must be gone, or genesis would deploy the slot twice + _, stale := SYSTEM_CONTRACTS["RESERVED_C2"] + require.False(t, stale, "RESERVED_C2 must not coexist with UNIVERSAL_CALLBACK") +} + +// The address x/ucallback filters logs on must round-trip through common.Address, +// since the hook compares against a parsed address, not the raw string. +func TestUniversalCallbackAddress_RoundTrips(t *testing.T) { + addr := common.HexToAddress(SYSTEM_CONTRACTS["UNIVERSAL_CALLBACK"].Address) + require.Equal(t, + "0x00000000000000000000000000000000000000c2", + strings.ToLower(addr.Hex())) +} diff --git a/x/uvalidator/keeper/ballot_hooks_multi.go b/x/uvalidator/keeper/ballot_hooks_multi.go new file mode 100644 index 00000000..c7684b09 --- /dev/null +++ b/x/uvalidator/keeper/ballot_hooks_multi.go @@ -0,0 +1,49 @@ +package keeper + +import ( + "errors" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/pushchain/push-chain-node/x/uvalidator/types" +) + +// MultiBallotHooks fans a ballot terminal transition out to several modules. +// +// Added for x/ucallback, which reacts to READ_RESULT terminals alongside +// x/uexecutor's INBOUND_TX handling — the extension the Hooks doc comment +// anticipated. Follows MultiUValidatorHooks. +type MultiBallotHooks []types.BallotHooks + +// NewMultiBallotHooks creates a new combined ballot hook instance. +func NewMultiBallotHooks(hooks ...types.BallotHooks) MultiBallotHooks { + return hooks +} + +// AfterBallotTerminal calls every hook, and does not stop at the first error. +// +// Terminal status is already decided by the time this runs; one module failing to +// clean up must not deny the others their notification. Errors are joined so the +// caller still sees everything that went wrong — though per the BallotHooks +// contract the caller logs and ignores them rather than blocking the transition. +func (mh MultiBallotHooks) AfterBallotTerminal( + ctx sdk.Context, + ballotID string, + ballotType types.BallotObservationType, + status types.BallotStatus, +) error { + ctx.Logger().Debug("hook: AfterBallotTerminal", + "ballot_id", ballotID, + "ballot_type", ballotType.String(), + "status", status.String(), + "hook_count", len(mh), + ) + + var errs []error + for _, h := range mh { + if err := h.AfterBallotTerminal(ctx, ballotID, ballotType, status); err != nil { + errs = append(errs, err) + } + } + return errors.Join(errs...) +} diff --git a/x/uvalidator/keeper/ballot_hooks_multi_test.go b/x/uvalidator/keeper/ballot_hooks_multi_test.go new file mode 100644 index 00000000..b2ece842 --- /dev/null +++ b/x/uvalidator/keeper/ballot_hooks_multi_test.go @@ -0,0 +1,58 @@ +package keeper_test + +import ( + "errors" + "testing" + + "cosmossdk.io/log" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" + + "github.com/pushchain/push-chain-node/x/uvalidator/keeper" + "github.com/pushchain/push-chain-node/x/uvalidator/types" +) + +type spyBallotHook struct { + calls int + err error +} + +func (s *spyBallotHook) AfterBallotTerminal( + sdk.Context, string, types.BallotObservationType, types.BallotStatus, +) error { + s.calls++ + return s.err +} + +func fire(t *testing.T, hooks keeper.MultiBallotHooks) error { + t.Helper() + return hooks.AfterBallotTerminal( + sdk.Context{}.WithLogger(log.NewNopLogger()), + "ballot-1", + types.BallotObservationType_BALLOT_OBSERVATION_TYPE_READ_RESULT, + types.BallotStatus_BALLOT_STATUS_PASSED, + ) +} + +func TestMultiBallotHooks_FansOutToAll(t *testing.T) { + a, b := &spyBallotHook{}, &spyBallotHook{} + require.NoError(t, fire(t, keeper.NewMultiBallotHooks(a, b))) + require.Equal(t, 1, a.calls) + require.Equal(t, 1, b.calls) +} + +// One module failing must not deny the others their notification — the terminal +// status is already decided by the time this runs. +func TestMultiBallotHooks_ErrorDoesNotStopLaterHooks(t *testing.T) { + failing := &spyBallotHook{err: errors.New("boom")} + after := &spyBallotHook{} + + err := fire(t, keeper.NewMultiBallotHooks(failing, after)) + require.Error(t, err) + require.ErrorContains(t, err, "boom") + require.Equal(t, 1, after.calls, "the hook after the failure still ran") +} + +func TestMultiBallotHooks_Empty(t *testing.T) { + require.NoError(t, fire(t, keeper.NewMultiBallotHooks())) +} diff --git a/x/uvalidator/types/ballot.pb.go b/x/uvalidator/types/ballot.pb.go index 111e99fc..4fd07807 100644 --- a/x/uvalidator/types/ballot.pb.go +++ b/x/uvalidator/types/ballot.pb.go @@ -72,6 +72,7 @@ const ( BallotObservationType_BALLOT_OBSERVATION_TYPE_OUTBOUND_TX BallotObservationType = 2 BallotObservationType_BALLOT_OBSERVATION_TYPE_TSS_KEY BallotObservationType = 3 BallotObservationType_BALLOT_OBSERVATION_TYPE_FUND_MIGRATION BallotObservationType = 4 + BallotObservationType_BALLOT_OBSERVATION_TYPE_READ_RESULT BallotObservationType = 5 ) var BallotObservationType_name = map[int32]string{ @@ -80,6 +81,7 @@ var BallotObservationType_name = map[int32]string{ 2: "BALLOT_OBSERVATION_TYPE_OUTBOUND_TX", 3: "BALLOT_OBSERVATION_TYPE_TSS_KEY", 4: "BALLOT_OBSERVATION_TYPE_FUND_MIGRATION", + 5: "BALLOT_OBSERVATION_TYPE_READ_RESULT", } var BallotObservationType_value = map[string]int32{ @@ -88,6 +90,7 @@ var BallotObservationType_value = map[string]int32{ "BALLOT_OBSERVATION_TYPE_OUTBOUND_TX": 2, "BALLOT_OBSERVATION_TYPE_TSS_KEY": 3, "BALLOT_OBSERVATION_TYPE_FUND_MIGRATION": 4, + "BALLOT_OBSERVATION_TYPE_READ_RESULT": 5, } func (x BallotObservationType) String() string { @@ -242,46 +245,47 @@ func init() { func init() { proto.RegisterFile("uvalidator/v1/ballot.proto", fileDescriptor_b9f9c8e0d3c818f3) } var fileDescriptor_b9f9c8e0d3c818f3 = []byte{ - // 616 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x94, 0xcf, 0x4e, 0xdb, 0x4a, - 0x14, 0xc6, 0x63, 0x07, 0x72, 0x2f, 0x73, 0xef, 0x0d, 0x66, 0x80, 0x5b, 0x93, 0xaa, 0x6e, 0x04, - 0x15, 0xa4, 0x48, 0xc4, 0x05, 0x16, 0x5d, 0xe7, 0xcf, 0x40, 0xdd, 0xa6, 0x76, 0xea, 0x19, 0x23, - 0xe8, 0x66, 0xe4, 0x24, 0xa3, 0xd8, 0xaa, 0xc9, 0x44, 0xf6, 0x24, 0x82, 0xb7, 0xe8, 0x1b, 0x74, - 0xd3, 0x45, 0x1f, 0xa5, 0x4b, 0x96, 0x5d, 0x56, 0xb0, 0xe9, 0x3b, 0x74, 0x53, 0x79, 0xcc, 0x9f, - 0x24, 0x85, 0x6e, 0xac, 0xa3, 0xef, 0xf7, 0x9d, 0xf3, 0xf9, 0x68, 0x3c, 0x06, 0xa5, 0xd1, 0xd8, - 0x8f, 0xc2, 0x9e, 0x2f, 0x78, 0x6c, 0x8e, 0x77, 0xcd, 0x8e, 0x1f, 0x45, 0x5c, 0x54, 0x87, 0x31, - 0x17, 0x1c, 0xfe, 0x77, 0xc7, 0xaa, 0xe3, 0xdd, 0xd2, 0x4a, 0x9f, 0xf7, 0xb9, 0x24, 0x66, 0x5a, - 0x65, 0xa6, 0xd2, 0x92, 0x7f, 0x1a, 0x0e, 0xb8, 0x29, 0x9f, 0x99, 0xb4, 0xfe, 0x53, 0x05, 0x85, - 0xba, 0x1c, 0x04, 0x8b, 0x40, 0x0d, 0x7b, 0xba, 0x52, 0x56, 0x2a, 0x0b, 0xae, 0x1a, 0xf6, 0x20, - 0x02, 0xff, 0x64, 0x11, 0x54, 0x9c, 0x0f, 0x99, 0xae, 0x96, 0x95, 0x4a, 0x71, 0xef, 0x59, 0x75, - 0x2a, 0xa8, 0x9a, 0xf5, 0x3a, 0x9d, 0x84, 0xc5, 0x63, 0x5f, 0x84, 0x7c, 0x40, 0xce, 0x87, 0xcc, - 0x05, 0x59, 0x63, 0x5a, 0xc3, 0x2d, 0xb0, 0xc8, 0xa2, 0xb0, 0x1f, 0x76, 0x22, 0x46, 0xc7, 0x5c, - 0xb0, 0x38, 0xd1, 0xf3, 0xe5, 0x7c, 0x65, 0xc1, 0x2d, 0xde, 0xc8, 0x47, 0x52, 0x85, 0x26, 0x98, - 0x4f, 0x79, 0xa2, 0xcf, 0x95, 0xf3, 0x95, 0xe2, 0xde, 0xda, 0x4c, 0x52, 0xea, 0x72, 0x59, 0x32, - 0x8a, 0x84, 0x9b, 0xf9, 0xe0, 0x73, 0xa0, 0x8d, 0xb9, 0x08, 0x07, 0x7d, 0x2a, 0x82, 0x98, 0x25, - 0x01, 0x8f, 0x7a, 0xfa, 0x7c, 0x59, 0xa9, 0xe4, 0xdd, 0xc5, 0x4c, 0x27, 0x37, 0x32, 0xdc, 0x07, - 0x85, 0x44, 0xf8, 0x62, 0x94, 0xe8, 0x05, 0xb9, 0xc6, 0xe3, 0x7b, 0xd7, 0xc0, 0xd2, 0xe2, 0x5e, - 0x5b, 0xe1, 0x0b, 0xb0, 0xd2, 0x89, 0x78, 0xf7, 0x03, 0x0d, 0x58, 0xd8, 0x0f, 0x04, 0xed, 0xc6, - 0xcc, 0x17, 0xac, 0xa7, 0xff, 0x25, 0x33, 0xa0, 0x64, 0xaf, 0x24, 0x6a, 0x64, 0x04, 0x56, 0xc1, - 0xf2, 0x54, 0x07, 0x3b, 0x1b, 0x86, 0xf1, 0xb9, 0xfe, 0xb7, 0x6c, 0x58, 0x9a, 0x68, 0x40, 0x12, - 0x6c, 0x7f, 0x52, 0xc0, 0xbf, 0x93, 0xd1, 0xf0, 0x09, 0x58, 0xab, 0xd7, 0x5a, 0x2d, 0x87, 0x50, - 0x4c, 0x6a, 0xc4, 0xc3, 0xd4, 0xb3, 0x71, 0x1b, 0x35, 0xac, 0x03, 0x0b, 0x35, 0xb5, 0x1c, 0x5c, - 0x03, 0xab, 0xd3, 0xb8, 0x8d, 0xec, 0xa6, 0x65, 0x1f, 0x6a, 0x0a, 0xd4, 0xc1, 0xca, 0x0c, 0xaa, - 0x61, 0x8c, 0x9a, 0x9a, 0x0a, 0x4b, 0xe0, 0xff, 0x69, 0xe2, 0xa2, 0xd7, 0xa8, 0x41, 0x50, 0x53, - 0xcb, 0xff, 0x3e, 0x10, 0x1d, 0xb7, 0x2d, 0x17, 0x35, 0xb5, 0xb9, 0xd2, 0xdc, 0x97, 0xcf, 0x86, - 0xb2, 0xfd, 0x43, 0x01, 0xab, 0xf7, 0x9e, 0x31, 0xdc, 0x02, 0x1b, 0xd7, 0xad, 0x4e, 0x1d, 0x23, - 0xf7, 0xa8, 0x46, 0x2c, 0xc7, 0xa6, 0xe4, 0xa4, 0x8d, 0x66, 0x5e, 0x7a, 0x13, 0xac, 0x3f, 0x64, - 0xb4, 0xec, 0xba, 0xe3, 0xd9, 0x4d, 0x4a, 0x8e, 0x35, 0xe5, 0x4f, 0x03, 0x1d, 0x8f, 0xdc, 0x1a, - 0x55, 0xb8, 0x01, 0x9e, 0x3e, 0x64, 0x24, 0x18, 0xd3, 0x37, 0xe8, 0x44, 0xcb, 0xc3, 0x6d, 0xb0, - 0xf9, 0x90, 0xe9, 0x20, 0x9d, 0xf4, 0xd6, 0x3a, 0x74, 0xa5, 0x76, 0xbb, 0x6a, 0x17, 0x80, 0xbb, - 0x6f, 0x2c, 0x3d, 0x89, 0x23, 0x87, 0x20, 0xea, 0x22, 0xec, 0xb5, 0x08, 0xb5, 0x1d, 0x42, 0x4f, - 0x10, 0xa1, 0xa9, 0x96, 0x2e, 0xf5, 0x08, 0x2c, 0x4f, 0x62, 0xec, 0x35, 0x1a, 0x08, 0x63, 0x4d, - 0x99, 0x05, 0x07, 0x35, 0xab, 0xe5, 0xb9, 0x48, 0x53, 0xb3, 0x90, 0xfa, 0xbb, 0xaf, 0x97, 0x86, - 0x72, 0x71, 0x69, 0x28, 0xdf, 0x2f, 0x0d, 0xe5, 0xe3, 0x95, 0x91, 0xbb, 0xb8, 0x32, 0x72, 0xdf, - 0xae, 0x8c, 0xdc, 0xfb, 0x97, 0xfd, 0x50, 0x04, 0xa3, 0x4e, 0xb5, 0xcb, 0x4f, 0xcd, 0xe1, 0x28, - 0x09, 0xba, 0x81, 0x1f, 0x0e, 0x64, 0xb5, 0x23, 0xcb, 0x9d, 0x01, 0xef, 0x31, 0xf3, 0xcc, 0x9c, - 0xf8, 0x09, 0xa4, 0xf7, 0x32, 0xe9, 0x14, 0xe4, 0x4d, 0xde, 0xff, 0x15, 0x00, 0x00, 0xff, 0xff, - 0x4e, 0x9b, 0x9c, 0x99, 0x1f, 0x04, 0x00, 0x00, + // 626 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x94, 0xc1, 0x4e, 0xdb, 0x4a, + 0x14, 0x86, 0x63, 0x27, 0xe4, 0x5e, 0xe6, 0xde, 0x1b, 0xcc, 0x00, 0xb7, 0x26, 0x55, 0xdd, 0x08, + 0x2a, 0x48, 0x91, 0x88, 0x0b, 0x2c, 0xba, 0x4e, 0xe2, 0x81, 0xba, 0x4d, 0xed, 0x74, 0x3c, 0x46, + 0xd0, 0xcd, 0xc8, 0x49, 0xac, 0xd8, 0xaa, 0xc9, 0x44, 0xf6, 0x24, 0x82, 0xb7, 0x68, 0x9f, 0xa0, + 0x9b, 0x2e, 0xfa, 0x28, 0x5d, 0xb2, 0xec, 0xb2, 0x82, 0xc7, 0xe8, 0xa6, 0xf2, 0x38, 0x94, 0x24, + 0x05, 0x36, 0xd1, 0xd1, 0xff, 0xfd, 0xe7, 0xfc, 0x39, 0x1e, 0x8f, 0x41, 0x79, 0x34, 0xf6, 0xa2, + 0xb0, 0xe7, 0x71, 0x16, 0xeb, 0xe3, 0x3d, 0xbd, 0xe3, 0x45, 0x11, 0xe3, 0xb5, 0x61, 0xcc, 0x38, + 0x83, 0xff, 0xdd, 0xb2, 0xda, 0x78, 0xaf, 0xbc, 0xda, 0x67, 0x7d, 0x26, 0x88, 0x9e, 0x56, 0x99, + 0xa9, 0xbc, 0xec, 0x9d, 0x85, 0x03, 0xa6, 0x8b, 0xdf, 0x4c, 0xda, 0xf8, 0x29, 0x83, 0x62, 0x43, + 0x0c, 0x82, 0x25, 0x20, 0x87, 0x3d, 0x55, 0xaa, 0x48, 0xd5, 0x45, 0x2c, 0x87, 0x3d, 0x88, 0xc0, + 0x3f, 0x59, 0x04, 0xe5, 0x17, 0x43, 0x5f, 0x95, 0x2b, 0x52, 0xb5, 0xb4, 0xff, 0xac, 0x36, 0x13, + 0x54, 0xcb, 0x7a, 0xed, 0x4e, 0xe2, 0xc7, 0x63, 0x8f, 0x87, 0x6c, 0x40, 0x2e, 0x86, 0x3e, 0x06, + 0x59, 0x63, 0x5a, 0xc3, 0x6d, 0xb0, 0xe4, 0x47, 0x61, 0x3f, 0xec, 0x44, 0x3e, 0x1d, 0x33, 0xee, + 0xc7, 0x89, 0x9a, 0xaf, 0xe4, 0xab, 0x8b, 0xb8, 0x74, 0x23, 0x1f, 0x0b, 0x15, 0xea, 0x60, 0x21, + 0xe5, 0x89, 0x5a, 0xa8, 0xe4, 0xab, 0xa5, 0xfd, 0xf5, 0xb9, 0xa4, 0xd4, 0x85, 0xfd, 0x64, 0x14, + 0x71, 0x9c, 0xf9, 0xe0, 0x73, 0xa0, 0x8c, 0x19, 0x0f, 0x07, 0x7d, 0xca, 0x83, 0xd8, 0x4f, 0x02, + 0x16, 0xf5, 0xd4, 0x85, 0x8a, 0x54, 0xcd, 0xe3, 0xa5, 0x4c, 0x27, 0x37, 0x32, 0x3c, 0x00, 0xc5, + 0x84, 0x7b, 0x7c, 0x94, 0xa8, 0x45, 0xb1, 0xc6, 0xe3, 0x3b, 0xd7, 0x70, 0x84, 0x05, 0x4f, 0xac, + 0xf0, 0x05, 0x58, 0xed, 0x44, 0xac, 0xfb, 0x81, 0x06, 0x7e, 0xd8, 0x0f, 0x38, 0xed, 0xc6, 0xbe, + 0xc7, 0xfd, 0x9e, 0xfa, 0x97, 0xc8, 0x80, 0x82, 0xbd, 0x12, 0xa8, 0x99, 0x11, 0x58, 0x03, 0x2b, + 0x33, 0x1d, 0xfe, 0xf9, 0x30, 0x8c, 0x2f, 0xd4, 0xbf, 0x45, 0xc3, 0xf2, 0x54, 0x03, 0x12, 0x60, + 0xe7, 0xb3, 0x04, 0xfe, 0x9d, 0x8e, 0x86, 0x4f, 0xc0, 0x7a, 0xa3, 0xde, 0x6a, 0xd9, 0x84, 0x3a, + 0xa4, 0x4e, 0x5c, 0x87, 0xba, 0x96, 0xd3, 0x46, 0x4d, 0xf3, 0xd0, 0x44, 0x86, 0x92, 0x83, 0xeb, + 0x60, 0x6d, 0x16, 0xb7, 0x91, 0x65, 0x98, 0xd6, 0x91, 0x22, 0x41, 0x15, 0xac, 0xce, 0xa1, 0xba, + 0xe3, 0x20, 0x43, 0x91, 0x61, 0x19, 0xfc, 0x3f, 0x4b, 0x30, 0x7a, 0x8d, 0x9a, 0x04, 0x19, 0x4a, + 0xfe, 0xcf, 0x81, 0xe8, 0xa4, 0x6d, 0x62, 0x64, 0x28, 0x85, 0x72, 0xe1, 0xeb, 0x17, 0x4d, 0xda, + 0xf9, 0x24, 0x83, 0xb5, 0x3b, 0xcf, 0x18, 0x6e, 0x83, 0xcd, 0x49, 0xab, 0xdd, 0x70, 0x10, 0x3e, + 0xae, 0x13, 0xd3, 0xb6, 0x28, 0x39, 0x6d, 0xa3, 0xb9, 0x3f, 0xbd, 0x05, 0x36, 0xee, 0x33, 0x9a, + 0x56, 0xc3, 0x76, 0x2d, 0x83, 0x92, 0x13, 0x45, 0x7a, 0x68, 0xa0, 0xed, 0x92, 0xdf, 0x46, 0x19, + 0x6e, 0x82, 0xa7, 0xf7, 0x19, 0x89, 0xe3, 0xd0, 0x37, 0xe8, 0x54, 0xc9, 0xc3, 0x1d, 0xb0, 0x75, + 0x9f, 0xe9, 0x30, 0x9d, 0xf4, 0xd6, 0x3c, 0xc2, 0x42, 0x53, 0x0a, 0x0f, 0x25, 0x63, 0x54, 0x37, + 0x28, 0x46, 0x8e, 0xdb, 0x22, 0xca, 0xc2, 0xe4, 0x99, 0x74, 0x01, 0xb8, 0x7d, 0x19, 0xd3, 0x23, + 0x3b, 0xb6, 0x09, 0x9a, 0x98, 0xa8, 0x65, 0x13, 0x7a, 0x8a, 0x08, 0x4d, 0xb5, 0x74, 0xfb, 0x47, + 0x60, 0x65, 0x1a, 0x3b, 0x6e, 0xb3, 0x89, 0x1c, 0x47, 0x91, 0xe6, 0xc1, 0x61, 0xdd, 0x6c, 0xb9, + 0x18, 0x29, 0x72, 0x16, 0xd2, 0x78, 0xf7, 0xed, 0x4a, 0x93, 0x2e, 0xaf, 0x34, 0xe9, 0xc7, 0x95, + 0x26, 0x7d, 0xbc, 0xd6, 0x72, 0x97, 0xd7, 0x5a, 0xee, 0xfb, 0xb5, 0x96, 0x7b, 0xff, 0xb2, 0x1f, + 0xf2, 0x60, 0xd4, 0xa9, 0x75, 0xd9, 0x99, 0x3e, 0x1c, 0x25, 0x41, 0x37, 0xf0, 0xc2, 0x81, 0xa8, + 0x76, 0x45, 0xb9, 0x3b, 0x60, 0x3d, 0x5f, 0x3f, 0xd7, 0xa7, 0xbe, 0x16, 0xe9, 0x05, 0x4e, 0x3a, + 0x45, 0x71, 0xe5, 0x0f, 0x7e, 0x05, 0x00, 0x00, 0xff, 0xff, 0x45, 0x8d, 0x9b, 0x0c, 0x48, 0x04, + 0x00, 0x00, } func (m *Ballot) Marshal() (dAtA []byte, err error) {