Repository navigation
Stellar RPC v30.0.1
Breaking Changes
- JSON-RPC batches with more than
MAX_REQUEST_BATCH_SIZEcalls (default 10) are now rejected with one error, and none of their calls run. simulateTransactionerror strings no longer include the event log or a backtrace. They now hold only the host error, such asHostError: Error(WasmVm, MissingValue). The diagnostic events are still returned in theeventsfield when--preflight-enable-debugis on.
Fixed
getTransaction,getTransactionsandgetLedgersno longer fail in JSON for deeply nested transactions. This changes wire behavior for BOTH rpcv1 and rpcv2 — the handlers are shared. WithxdrFormat: "json", a transaction whose XDR was deeper than the JSON converter's limit (depth 500) used to fail with-32603("xdr_to_json() failed: ... depth limit exceeded"), although stellar-core accepts transactions up to depth 1000. IngetTransactionsandgetLedgers, one such transaction failed the whole page, so the other transactions on that page could not be read in JSON either. Base64 responses were not affected. The converter now accepts every depth that stellar-core accepts. Clients need no changes.simulateTransactionnow says when the network's protocol is unsupported. Each stellar-rpc release can simulate on two protocols only, the ones its bundled soroban hosts support (29 and 30 for v30). On a network running an older protocol, simulation used to fail with an opaqueHostError: Error(Context, InternalError)and no diagnostic events. Simulation on any unsupported protocol now fails with an error that names the network's protocol and the protocols this stellar-rpc supports (#1163).getLedgersno longer rejects its own cursor at the tip. This changes wire behavior for BOTH rpcv1 and rpcv2 — the handler is shared. Resending the cursor of the last page used to fail with-32602("cursor must be between the oldest ledger ... and the latest ledger ...") until the next ledger closed — the same code a malformed cursor gets, so a poller could not tell "wait and retry" from "bad cursor". A cursor at or past the tip now returns an empty page with the cursor echoed back. A cursor below the oldest ledger still errors (that data is gone), and an explicitstartLedgerabove the tip still errors (only the server-issued token gets the echo).getTransactionscursor no longer breaks a caught-up poller. This changes wire behavior for BOTH rpcv1 and rpcv2 — the handler is shared. Two long-standing bugs, one fix: the returnedcursoris now never below the request's cursor; at the tip, the request's cursor is echoed back. Before this fix: (1) a cursor at or above the node's latest ledger returned the literal cursor"0", and resending it failed every poll with-32602— the client was stuck until it discarded its cursor (reported in #745); (2) a cursor at a fully-consumed ledger returned a cursor pointing back at that ledger's start, and the next poll re-delivered all of its transactions as duplicates. Clients need no changes: the returned cursor now always does what the docs promise — fetch what comes next.simulateTransactionandsendTransactionno longer reject a transaction whose decoded form would exceed 1 MB, such as a contract call with a 6,000-element vector argument. The RPC now reads the XDR in requests without decoding it.sendTransactionwithxdrFormat: jsonno longer fails withcouldn't decode eventswhen stellar-core rejects a classic transaction. It now returns the error result, as the base64 format already did.getLedgerEntriesno longer fails with a 404 error just after a ledger closes. Ledger entry reads forgetLedgerEntriesandsimulateTransactionnow wait for stellar-core's query server to reach the ledger of the read.- A failed ledger entry fetch now fails
simulateTransactioninstead of simulating as if the entry were missing, which could return a wrong result that looked successful. - rpcv1 ingests a ledger whatever the size of its meta. A ledger whose meta was larger than 256 MiB stopped ingestion, and SQLite's 1 GB blob limit would have stopped it at the first ledger over that size.
Changed
- The memory a node holds in responses waiting to be written is now capped (rpcv1:
MAX_TOTAL_RESPONSE_BYTES, default 2 GiB; rpcv2:[service].max_total_response_bytes, default 4 GiB;0means no limit). At the cap, a response over 4 KiB fails with-32098, as a call to a full method queue does, and a response larger than the cap always fails, with a message to request fewer items. Theglobal_total_response_bytes_limitcounter counts those failures. - A response now gets one write deadline, 30 seconds plus one second per MiB, and a client that has not read it by then is cut off.
- A request past its method's execution limit is now answered with
-32001once its handler has stopped, so the handler no longer keeps running after the answer. - With
xdrFormat: json, a request now fails if one XDR value would convert to more thanMAX_JSON_CONVERSION_BYTESof JSON (default 128 MiB; rpcv2:[service].max_json_conversion_bytes, default 256 MiB). The largest pubnet ledgers convert to about 10 MiB. - A new setting,
MAX_RESPONSE_BYTES(rpcv2:[service].max_response_bytes), limits the XDR or JSON one response may carry. It is off by default (0), so responses do not change until an operator sets it. When it is set,getLedgerEntriesfails with-32602if its entries would exceed it, andgetLedgers,getTransactionsandgetEvents, and rpcv2'squeryEvents, end a page early, with a cursor, before an item that would take the page past it. A page always holds at least one item, and a page shorter thanlimitno longer means the data has run out. At 128 MiB, rpcv1's default 50-ledgergetLedgerspage holds about 25 ledgers in JSON format and about 48 in base64. simulateTransactionruns each simulation in a separate worker process. stellar-rpc starts--preflight-worker-countworkers ([service.preflight].worker_countin rpcv2) and replaces any worker that exits. A worker still simulating when its call reachesMAX_SIMULATE_TRANSACTION_EXECUTION_DURATION([service.methods.simulateTransaction].max_execution_durationin rpcv2) is killed. A simulation that runs out of time, whether it is killed or stops waiting for a ledger read, fails with the same timeout error as before. A simulation whose worker runs out of memory or exits fails withsimulation exceeded its resource limits or failed. Thepreflight_pool_worker_exits_totalmetric counts worker exits by cause.- Each preflight worker limits the heap memory the simulation library may hold, to 8 times the network's per-transaction memory limit (320 MiB on mainnet today) or to the bytes
--preflight-simulation-memory-limit([service.preflight].simulation_memory_limitin rpcv2) sets, which must be at least 16000000. A simulation that passes the limit fails withsimulation exceeded its resource limits or failed, and its worker exits and is replaced. When the workers first report the limit, and whenever it changes, stellar-rpc logs the number of workers, the limit and their product. Plan for about the limit + 128 MiB per worker, on top of what stellar-rpc and captive core use. simulateTransactioncalls no longer take one of the handler slots that all other methods share. A call that finds every preflight worker busy waits for one of the--preflight-worker-queue-size([service.preflight].worker_queue_sizein rpcv2) queue places, and otherwise fails at once with the new JSON-RPC error-32004(preflight queue full; retry later) instead of a result whoseerrorispreflight queue full, so clients can tell a busy server from a failed simulation. The queue now defaults to the larger of the number of CPUs andMAX_REQUEST_BATCH_SIZE([service].max_request_batch_sizein rpcv2), since the calls of one batch start at once. The request duration metric now labels such errors by their code, and any other handler error without a code aserrorrather thanok.- The defaults sized by CPU count now use the number of CPUs the process may use (
GOMAXPROCS), which follows a container's CPU limit: the number of handlers that run at once,--preflight-worker-count,--preflight-worker-queue-sizeand--stellar-captive-core-http-query-thread-pool-size, and the matching rpcv2 settings. getTransactionsnow scans at most 10,000 ledgers per request. On a sparse range a page can come back short — or even empty — while still carrying acursor, so a response shorter thanlimitno longer implies end-of-data. Every response carries acursor; to tell a sparse scan window from the tip, compare the cursor's ledger part againstlatestLedgerand keep paging while it is below (#908).getEventsnow rejects malformed contract IDs in filters with-32602: aC…string with a valid checksum but wrong-length payload used to decode and silently match nothing, and now errors under the SDK's stricter SEP-23 strkey parsing (#908).getTransactionsnow returns-32603(internal error) instead of-32602(invalid params) when the node cannot parse a transaction out of its own stored ledger meta in both rpcv1 and rpcv2. Because the request parameters are valid in that case, the previous error was misleading (#962).getTransactionandgetTransactionsnow serve transactions with legacyTransactionMetaV0. This changes wire behavior for BOTH rpcv1 and rpcv2 (though in practice only a full-history node retains ledgers old enough to carry V0 meta). Such a transaction used to fail the request with-32603("unsupported TransactionMeta version: 0"), and ingetTransactionsone V0 transaction failed the whole page. They are now returned like any other pre-Soroban transaction, with no events (#962).
Contributors
Full Changelog: v30.0.0...v30.0.1