github stellar/stellar-rpc v30.0.1

2 hours ago

Stellar RPC v30.0.1

Breaking Changes

  • JSON-RPC batches with more than MAX_REQUEST_BATCH_SIZE calls (default 10) are now rejected with one error, and none of their calls run.
  • simulateTransaction error strings no longer include the event log or a backtrace. They now hold only the host error, such as HostError: Error(WasmVm, MissingValue). The diagnostic events are still returned in the events field when --preflight-enable-debug is on.

Fixed

  • getTransaction, getTransactions and getLedgers no longer fail in JSON for deeply nested transactions. This changes wire behavior for BOTH rpcv1 and rpcv2 — the handlers are shared. With xdrFormat: "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. In getTransactions and getLedgers, 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.
  • simulateTransaction now 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 opaque HostError: 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).
  • getLedgers no 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 explicit startLedger above the tip still errors (only the server-issued token gets the echo).
  • getTransactions cursor 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 returned cursor is 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.
  • simulateTransaction and sendTransaction no 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.
  • sendTransaction with xdrFormat: json no longer fails with couldn't decode events when stellar-core rejects a classic transaction. It now returns the error result, as the base64 format already did.
  • getLedgerEntries no longer fails with a 404 error just after a ledger closes. Ledger entry reads for getLedgerEntries and simulateTransaction now wait for stellar-core's query server to reach the ledger of the read.
  • A failed ledger entry fetch now fails simulateTransaction instead 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; 0 means 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. The global_total_response_bytes_limit counter 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 -32001 once 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 than MAX_JSON_CONVERSION_BYTES of 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, getLedgerEntries fails with -32602 if its entries would exceed it, and getLedgers, getTransactions and getEvents, and rpcv2's queryEvents, 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 than limit no longer means the data has run out. At 128 MiB, rpcv1's default 50-ledger getLedgers page holds about 25 ledgers in JSON format and about 48 in base64.
  • simulateTransaction runs each simulation in a separate worker process. stellar-rpc starts --preflight-worker-count workers ([service.preflight].worker_count in rpcv2) and replaces any worker that exits. A worker still simulating when its call reaches MAX_SIMULATE_TRANSACTION_EXECUTION_DURATION ([service.methods.simulateTransaction].max_execution_duration in 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 with simulation exceeded its resource limits or failed. The preflight_pool_worker_exits_total metric 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_limit in rpcv2) sets, which must be at least 16000000. A simulation that passes the limit fails with simulation 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.
  • simulateTransaction calls 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_size in rpcv2) queue places, and otherwise fails at once with the new JSON-RPC error -32004 (preflight queue full; retry later) instead of a result whose error is preflight 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 and MAX_REQUEST_BATCH_SIZE ([service].max_request_batch_size in 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 as error rather than ok.
  • 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-size and --stellar-captive-core-http-query-thread-pool-size, and the matching rpcv2 settings.
  • getTransactions now scans at most 10,000 ledgers per request. On a sparse range a page can come back short — or even empty — while still carrying a cursor, so a response shorter than limit no longer implies end-of-data. Every response carries a cursor; to tell a sparse scan window from the tip, compare the cursor's ledger part against latestLedger and keep paging while it is below (#908).
  • getEvents now rejects malformed contract IDs in filters with -32602: a C… 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).
  • getTransactions now 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).
  • getTransaction and getTransactions now serve transactions with legacy TransactionMeta V0. 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 in getTransactions one 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

Don't miss a new stellar-rpc release

NewReleases is sending notifications on new releases.