linera-io/linera-protocol · error

SetRpcEndpoint requires an authenticated signer

Error message

SetRpcEndpoint requires an authenticated signer

What it means

SetRpcEndpoint is owner-only: the contract expects runtime.authenticated_owner() to return Some, i.e. the executing transaction must carry the bridge-chain owner's signature. When it panics, the whole transaction aborts and the previously stored rpc_endpoint is left unchanged. Note that even after passing this gate, validate_rpc_endpoint will dial the endpoint and abort on failure.

Source

Thrown at linera-bridge/contracts/evm-bridge/src/contract.rs:105

                        .verified_block_hashes
                        .insert(&block_hash)
                        .expect("failed to insert verified block hash");
                }
            }
            BridgeOperation::RegisterFungibleBridge { address } => {
                self.runtime
                    .authenticated_owner()
                    .expect("RegisterFungibleBridge requires an authenticated signer");
                assert!(
                    self.state.bridge_contract_address.get().is_none(),
                    "bridge contract address is already registered and cannot be changed"
                );
                self.state.bridge_contract_address.set(Some(address));
            }
            BridgeOperation::SetRpcEndpoint { rpc_endpoint } => {
                self.runtime
                    .authenticated_owner()
                    .expect("SetRpcEndpoint requires an authenticated signer");
                self.validate_rpc_endpoint(&rpc_endpoint).await;
                self.state.rpc_endpoint.set(rpc_endpoint);
            }
            BridgeOperation::Burn { amount, evm_target } => {
                self.initiate_burn(amount, evm_target);
            }
        }
    }

    async fn execute_message(&mut self, message: BridgeMessage) {
        match message {
            BridgeMessage::Burn { amount, evm_target } => {
                // A bouncing delivery is a no-op: the funding transfer is part
                // of the same outgoing bundle and bounces on its own, refunding
                // the user on their chain via wrapped-fungible's Credit handler.
                let is_bouncing = self
                    .runtime
                    .message_is_bouncing()

View on GitHub (pinned to 6c226ddcb3)

Solutions

  1. Sign and submit SetRpcEndpoint with the bridge chain owner's key
  2. Confirm the target chain is the bridge chain and the wallet actually owns it (linera wallet show)
  3. Pre-flight the new endpoint's chain ID (see validate_rpc_endpoint) so the signed transaction does not abort after the auth check
  4. In your own contract builds, turn the expect into an assert! for a clearer rejection

Example fix

// before
self.runtime
    .authenticated_owner()
    .expect("SetRpcEndpoint requires an authenticated signer");

// after
assert!(
    self.runtime.authenticated_owner().is_some(),
    "SetRpcEndpoint requires an authenticated signer"
);
// Caller-side: ensure the submission client signs with the bridge chain
// owner key, e.g. linera process-and-transfer --signer <owner-key> ...
Defensive patterns

Strategy: validation

Validate before calling

// Pre-flight both gates before spending a transaction:
// 1) signer must be the bridge chain owner
assert_eq!(wallet.owner_of(bridge_chain_id), Some(signer.public()));
// 2) endpoint must answer with the configured chain ID
let id = http_post_json(&rpc_endpoint, eth_chain_id_request()).await?;
assert_eq!(id, format!("0x{source_chain_id:x}"));
client.submit(bridge_chain_id, BridgeOperation::SetRpcEndpoint { rpc_endpoint });

Try / catch

// The panic aborts the SetRpcEndpoint transaction atomically; catch nothing,
// instead inspect the block's rejected-transaction error, fix signer or
// endpoint, and resubmit. State (old endpoint) is unchanged.

Prevention

When it happens

Trigger: Submitting SetRpcEndpoint signed by a non-owner key; executing it via a cross-application session with no authenticated signer; running an ops script that authenticates with a read-only or rotated key after the owner key changed.

Common situations: Rotating the bridge owner key and forgetting to update deployment automation; pointing an ops pipeline at the bridge chain with a watcher wallet instead of the owner wallet; testnets where chains are created by one account and operated by another.

Understand the failure class

Related errors


AI-assisted analysis of linera-io/linera-protocol@6c226ddcb3 (2026-08-22). Data as JSON: /api/errors/e5e821565052e83f. Report an issue: GitHub.