## Context See `proposal.md` for motivation. `SolanaBlockChainImpl` currently serializes every RPC request through a synchronized `sendThrottled()` method, sleeps until five seconds have elapsed since the preceding RPC response, performs HTTP while holding the monitor, and records completion time in `finally`. Monitor acquisition is neither interruptible nor deadline-aware, while issue #67 requires both without changing existing RPC behavior. ## Goals / Non-Goals **Goals:** - Preserve one shared five-second gate for all RPC calls while allowing awaiting calls to stop at a monotonic deadline. - Keep definitive transaction state, timeout, protocol failure, and interruption as distinct outcomes. - Strictly validate all wire data that controls a returned outcome. - Keep the API and outcome types generic to Solana rather than any consuming domain. **Non-Goals:** - Combining submission and awaiting, resubmission, WebSockets, signature subscriptions, or blockhash-expiration inference. - Updating any existing wallet, Jupiter, burn, Evelyn, or Discord consumer. - Adding automated tests or test-only transport, time, or throttling seams in this implementation. ## Decisions ### Replace the intrinsic monitor with one interruptible shared lock A private `ReentrantLock` will serialize all RPC traffic. Existing calls acquire it interruptibly, perform the same five-second wait and HTTP exchange, update the shared completion timestamp in `finally`, and release it. Awaiting calls use timed `tryLock` with their remaining deadline. A separate polling lock or rate limiter was rejected because it would violate the shared throttle and permit polling to interfere unpredictably with other calls. ### Measure shared throttling and awaiting deadlines monotonically The completion timestamp and deadline calculations use `System.nanoTime()`. A small private deadline value tracks the call's start and saturated timeout nanoseconds and computes remaining time by elapsed duration. Wall-clock time was rejected because clock adjustments could extend or shorten both throttling and the caller's timeout. ### Build each status HTTP request only after gate and throttle admission The deadline-aware send path acquires the gate and waits only up to the remaining deadline. Once admitted, it creates a request whose `HttpRequest.timeout` equals the then-current remaining duration. A request-timeout exception is translated to `TIMED_OUT`; other I/O failures remain `IOException`. Building the request after admission avoids assigning the full original timeout to an HTTP exchange that starts after gate/throttle delay. ### Return an internal no-request signal on deadline expiry The deadline-aware send helper returns no response when the deadline expires before request start. The public loop converts this only to the invariant `TIMED_OUT` value. This keeps deadline expiry separate from communication/protocol exceptions and ensures a previously seen lower-commitment slot cannot leak into the timeout result. ### Parse only authoritative signature-status fields Each response must contain a successful HTTP result, no JSON-RPC error, and exactly one `result.value` element. A null element remains inconclusive. A status object requires a Long-representable non-negative `slot` and recognized `confirmationStatus`; only after its commitment satisfies the request is `err` interpreted as success or failure. `result.context`, `confirmations`, and legacy `status` are ignored. ### Preserve the complete on-chain error as compact JSON Jackson's compact serialization of the non-null `err` node becomes `failureDetails`. The blockchain layer does not classify program-specific errors. Any issue outside this `err` node remains an exception or timeout rather than `FAILED`. ### Validate transaction signatures with the existing Base58 implementation The reference implementation reuses its existing private Base58 decoder and requires exactly 64 decoded bytes before entering the RPC gate. Introducing a second codec dependency or general transaction parser was rejected as unrelated scope. ### Make cached awaiting a transparent pass-through `CachedSolanaBlockChain.awaitTransaction` calls its delegate directly. Transaction status is deadline-sensitive and mutable, so cache keys, reuse, and in-flight deduplication would violate the contract. ## Risks / Trade-offs - [An HTTP client can complete at the edge of its timeout after the monotonic deadline] → Use the remaining deadline as the request timeout and re-check the deadline before interpreting an inconclusive response; this is the strongest practical bound offered by Java `HttpClient`. - [Replacing synchronization changes the internal locking primitive] → Keep the same lock scope, completion-based five-second spacing, and exception behavior for every existing RPC operation. - [No automated deterministic coverage is added now] → Keep deadline, parsing, and gate concerns in narrow private methods and document that focused tests remain deferred by explicit task instruction. ## Migration Plan This is additive at the public API. Existing implementations in this repository are updated together, while existing consumers remain unchanged. Rollback removes the new method/types and restores the prior private monitor without data migration.