Conversation
📝 WalkthroughWalkthroughThese changes introduce sender-type-based signature verification, wire-encoded transaction formats, and a post-bootstrap transaction hook. The verifier system shifts from tx-type dispatch to sender-type dispatch to support custom authentication mechanisms like Ed25519, enabling non-EOA senders alongside Ethereum secp256k1 EOAs. Changes
Sequence DiagramsequenceDiagram
participant Client
participant Gateway as EthGateway
participant Registry as VerifierRegistry
participant Verifier as SignatureVerifierDyn
participant Mempool
Client->>Gateway: send raw transaction (wire-encoded)
alt EOA Envelope Format
Gateway->>Gateway: decode as TxEnvelope
Gateway->>Registry: verify_payload(EOA_SECP256K1, TxPayload::Eoa(...))
else Custom Wire Format
Gateway->>Gateway: detect wire magic, decode TxContext
Gateway->>Gateway: extract TxPayload::Custom
Gateway->>Registry: verify_payload(sender_type, TxPayload::Custom(...))
end
Registry->>Verifier: verify(&payload)
alt Valid Signature
Verifier-->>Registry: Ok(())
Registry-->>Gateway: Ok(verified_context)
else Invalid/Unsupported
Verifier-->>Registry: Err(signature/sender_type error)
Registry-->>Gateway: Err(GatewayError)
Gateway-->>Client: Reject
end
Gateway->>Mempool: submit verified TxContext
Mempool-->>Client: success / mempool entry
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (13)
docker-compose.testapp.yml (1)
2-26: Consider adding a health check and restart policy.For improved reliability during development and CI testing, you may want to add:
healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8545"] interval: 10s timeout: 5s retries: 3 restart: unless-stoppedThis helps with container orchestration and ensures the service recovers from transient failures.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docker-compose.testapp.yml` around lines 2 - 26, Add a container healthcheck and restart policy to the testapp service in docker-compose.testapp.yml: under the service named "testapp" add a healthcheck that uses a CMD curl -f against http://localhost:8545 with interval 10s, timeout 5s and retries 3, and set restart to "unless-stopped" so the container is automatically restarted on transient failures; ensure these keys are placed alongside existing "ports", "environment", and "volumes" entries for the testapp service.bin/testapp/tests/mempool_e2e.rs (4)
577-581: Hardcoded nonce limits test reusability.The nonce is hardcoded to
0inEd25519AuthPayload. While this works for the single-transaction test, consider parameterizing it inEd25519CustomTxBuildInputfor future multi-transaction test scenarios.Suggested enhancement
struct Ed25519CustomTxBuildInput<'a> { tx_template_signer: &'a SigningKey, auth_signer: &'a Ed25519SigningKey, chain_id: u64, token_address: Address, recipient_account_id: AccountId, transfer_amount: u128, sender_account_id: AccountId, + nonce: u64, }Then use
input.nonceinstead of the literal0.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@bin/testapp/tests/mempool_e2e.rs` around lines 577 - 581, Ed25519AuthPayload is being constructed with a hardcoded nonce (0); change the code to take the nonce from the transaction builder input instead. Update the builder/input struct (Ed25519CustomTxBuildInput) to include a nonce field if it doesn't exist, pass that input through to the test, and replace the literal 0 with input.nonce when constructing auth_payload in the test where Ed25519AuthPayload and auth_payload are created so multi-transaction tests can supply different nonces.
802-806: Clarify the scope of the local verifier registry.The
SignatureVerifierRegistrycreated here is used only to verify the payload before submission, but it's not integrated into the actual block execution path (the STF). This is fine for testing the verifier logic in isolation, but consider adding a comment clarifying that the production path would need the registry configured in the STF/gateway.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@bin/testapp/tests/mempool_e2e.rs` around lines 802 - 806, The local SignatureVerifierRegistry created here (SignatureVerifierRegistry::new(), registry.register_dyn(sender_types::CUSTOM, Ed25519PayloadVerifier), and the call to registry.verify_payload(sender_types::CUSTOM, tx_context.payload())) is only being used to test the verifier logic prior to submission and is not wired into the STF/block execution path; add a concise comment above this block stating that this registry is local to the test and that in production the verifier registry must be configured and injected into the STF/gateway so the block execution path uses the same verifiers.
91-105: Error code collision withEd25519PayloadVerifier.Error codes 0x71-0x74 defined here overlap with those used (or suggested) in
Ed25519PayloadVerifier(lines 59-77). If both components are used in the same error path, distinguishing the failure source becomes difficult.Consider using a separate range for account-level errors vs verifier-level errors, or documenting the error code allocation.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@bin/testapp/tests/mempool_e2e.rs` around lines 91 - 105, The error codes 0x71–0x74 in the functions err_invalid_auth_payload, err_nonce_mismatch, err_invalid_public_key, and err_invalid_signature collide with those used by Ed25519PayloadVerifier; change these account-level error functions to return codes from a distinct, non-overlapping range (e.g., bump to 0x80–0x83 or define an ACCOUNT_ERROR_BASE constant) and update any tests/comments accordingly so verifier vs account errors are unambiguous, or alternatively add a clear documented allocation comment that reserves 0x71–0x74 for verifier errors and reassign account errors to a different range.
56-79: Consider using distinct error codes for different failure modes.Lines 59, 62, 64, 65, 70, and 71 all return
ErrorCode::new(0x75)for different error conditions (invalid payload type, Borsh decode failures, missing invoke request, encode failure). This makes debugging difficult when errors occur.Suggested distinct error codes
impl SignatureVerifierDyn for Ed25519PayloadVerifier { fn verify(&self, payload: &TxPayload) -> SdkResult<()> { let TxPayload::Custom(bytes) = payload else { - return Err(ErrorCode::new(0x75)); + return Err(ErrorCode::new(0x70)); // Invalid payload type }; let intent: EthIntentPayload = - borsh::from_slice(bytes).map_err(|_| ErrorCode::new(0x75))?; + borsh::from_slice(bytes).map_err(|_| ErrorCode::new(0x71))?; // Intent decode error let decoded: Ed25519EthIntentProof = - borsh::from_slice(&intent.auth_proof).map_err(|_| ErrorCode::new(0x75))?; + borsh::from_slice(&intent.auth_proof).map_err(|_| ErrorCode::new(0x72))?; // Proof decode error let envelope = intent.decode_envelope().map_err(|_| ErrorCode::new(0x75))?; let invoke_request = envelope .to_invoke_requests() .into_iter() .next() - .ok_or_else(|| ErrorCode::new(0x75))?; - let request_digest = keccak256(&invoke_request.encode().map_err(|_| ErrorCode::new(0x75))?); + .ok_or_else(|| ErrorCode::new(0x73))?; // No invoke request + let request_digest = keccak256(&invoke_request.encode().map_err(|_| ErrorCode::new(0x74))?);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@bin/testapp/tests/mempool_e2e.rs` around lines 56 - 79, The verify implementation in Ed25519PayloadVerifier (impl SignatureVerifierDyn for Ed25519PayloadVerifier -> fn verify) collapses multiple failure modes into ErrorCode::new(0x75), hindering debugging; update each failure site (the TxPayload match arm for TxPayload::Custom, both borsh::from_slice calls for EthIntentPayload and Ed25519EthIntentProof, intent.decode_envelope(), to_invoke_requests().next() missing-case, and invoke_request.encode()) to return distinct ErrorCode values (e.g., 0x75..0x7A) so callers can distinguish invalid payload type, intent decode error, auth_proof decode error, envelope decode error, missing invoke request, and encode error respectively; change the Err(...) and map_err(...) invocations to use the new unique ErrorCode::new(...) values while keeping existing shapes and mapping locations intact (match arm, borsh::from_slice map_err, decode_envelope map_err, ok_or_else for next, encode map_err).docker/evd/Dockerfile (1)
9-12: The fallbackrustup toolchain installwithout arguments may not work as intended.When
rustup show active-toolchainfails (toolchain not installed), the fallbackrustup toolchain installwithout specifying a toolchain name won't install anything meaningful. The command requires either a toolchain name argument or should rely on rustup's automatic toolchain installation.Consider using
rustup showwhich triggers auto-install fromrust-toolchain.toml:Proposed fix
-RUN rustup show active-toolchain || rustup toolchain install +RUN rustup showAlternatively, if you want explicit control:
RUN rustup toolchain install "$(cat rust-toolchain.toml | grep channel | cut -d'"' -f2)"🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docker/evd/Dockerfile` around lines 9 - 12, The fallback RUN line using "rustup show active-toolchain || rustup toolchain install" won't install a specific toolchain; update it to trigger auto-install from rust-toolchain.toml by replacing the fallback with a single "rustup show" (which consults rust-toolchain.toml) or explicitly install the channel parsed from rust-toolchain.toml; locate the COPY rust-toolchain.toml ./rust-toolchain.toml and the RUN rustup show active-toolchain || rustup toolchain install lines and either call rustup show alone or extract the "channel" from rust-toolchain.toml and pass it to rustup toolchain install so a concrete toolchain is installed.crates/app/tx/eth/src/eoa_registry.rs (1)
185-213: Potential inconsistent mapping state when forward mapping exists but reverse is missing.In
ensure_eoa_mapping, when the forward mapping (address -> account_id) exists and matches, but the reverse mapping (account_id -> address) does not exist (line 197 returnsNone), the function falls through to line 205 which checks only the reverse mapping. If the reverse doesn't exist, it creates both mappings viaset_mapping.However, at line 201, if the forward exists and matches, but the reverse also exists and matches, it returns
Ok(())early. This is correct.The issue is at line 202: if
lookup_address_in_envreturnsNone(reverse doesn't exist), the code exits the outerifblock and falls to line 205. This appears to be intentional fall-through behavior, but the nested structure makes it harder to follow.Consider simplifying the logic for clarity:
♻️ Suggested clearer structure
pub fn ensure_eoa_mapping( address: Address, account_id: AccountId, env: &mut dyn Environment, ) -> SdkResult<()> { - if let Some(existing) = lookup_account_id_in_env(address, env)? { - if existing != account_id { - return Err(ERR_ADDRESS_ACCOUNT_CONFLICT); - } - if let Some(existing_addr) = lookup_address_in_env(account_id, env)? { - if existing_addr != address { - return Err(ERR_ADDRESS_ACCOUNT_CONFLICT); - } - return Ok(()); - } - } - - if let Some(existing_addr) = lookup_address_in_env(account_id, env)? { - if existing_addr != address { - return Err(ERR_ADDRESS_ACCOUNT_CONFLICT); - } - return set_mapping(address, account_id, env); - } - - set_mapping(address, account_id, env) + let forward = lookup_account_id_in_env(address, env)?; + let reverse = lookup_address_in_env(account_id, env)?; + + // Validate consistency of any existing mappings + if let Some(existing_id) = forward { + if existing_id != account_id { + return Err(ERR_ADDRESS_ACCOUNT_CONFLICT); + } + } + if let Some(existing_addr) = reverse { + if existing_addr != address { + return Err(ERR_ADDRESS_ACCOUNT_CONFLICT); + } + } + + // If both mappings already exist and are consistent, nothing to do + if forward.is_some() && reverse.is_some() { + return Ok(()); + } + + // Create or complete the mapping + set_mapping(address, account_id, env) }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@crates/app/tx/eth/src/eoa_registry.rs` around lines 185 - 213, The current branching in ensure_eoa_mapping is confusing and can be simplified: first call lookup_account_id_in_env(address) and if Some(existing) and existing != account_id return ERR_ADDRESS_ACCOUNT_CONFLICT; then call lookup_address_in_env(account_id) and if Some(existing_addr) and existing_addr != address return ERR_ADDRESS_ACCOUNT_CONFLICT; if both lookups returned Some and they match return Ok(()); otherwise call set_mapping(address, account_id, env). Update ensure_eoa_mapping to use lookup_account_id_in_env, lookup_address_in_env, ERR_ADDRESS_ACCOUNT_CONFLICT, and set_mapping in that order to make the logic linear and avoid the nested fall-through.crates/app/tx/eth/src/gateway.rs (2)
163-184: Error mapping may obscure the actual failure reason.When
verify_payloadfails, the error is mapped by inspecting the chain ID post-hoc (lines 170-179). If the signature is invalid and the chain ID is wrong, this returnsInvalidChainIdrather thanInvalidSignature. This could mislead debugging efforts.Consider verifying chain ID before signature verification for clearer error semantics:
♻️ Suggested refactor
pub fn verify_envelope(&self, envelope: TxEnvelope) -> Result<TxContext, GatewayError> { + // Validate chain ID first for clearer error reporting + match envelope.chain_id() { + Some(id) if id != self.chain_id => { + return Err(GatewayError::InvalidChainId { + expected: self.chain_id, + actual: Some(id), + }); + } + None => { + return Err(GatewayError::InvalidChainId { + expected: self.chain_id, + actual: None, + }); + } + _ => {} + } + let payload = TxPayload::Eoa(Box::new(envelope.clone())); - // Verify chain ID and signature self.verifier .verify_payload(sender_type::EOA_SECP256K1, &payload) - .map_err(|_| match envelope.chain_id() { - Some(id) if id != self.chain_id => GatewayError::InvalidChainId { - expected: self.chain_id, - actual: Some(id), - }, - None => GatewayError::InvalidChainId { - expected: self.chain_id, - actual: None, - }, - _ => GatewayError::InvalidSignature, - })?; + .map_err(|_| GatewayError::InvalidSignature)?;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@crates/app/tx/eth/src/gateway.rs` around lines 163 - 184, In verify_envelope, check the envelope chain ID against self.chain_id before calling self.verifier.verify_payload so chain-id mismatches return GatewayError::InvalidChainId deterministically; only if the chain ID matches (or is absent if that’s acceptable) proceed to call verify_payload and map its failure to GatewayError::InvalidSignature (or propagate the existing mapping for None/Some mismatches handled earlier); keep the final TxContext::new(envelope, self.base_fee).ok_or(GatewayError::ContractCreationNotSupported) unchanged.
187-218: Consider adding tests for new public API methods.The new
register_payload_verifier,supports_sender_type, andverify_contextmethods lack direct test coverage. While the underlying registry is tested separately, gateway-level integration tests would help ensure the wiring is correct.Would you like me to generate test cases for the new gateway methods?
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@crates/app/tx/eth/src/gateway.rs` around lines 187 - 218, Add integration tests in the existing tests module for EthGateway that exercise the new public API: call register_payload_verifier on an EthGateway instance to register a mock verifier and assert it is accepted (and errors handled), call supports_sender_type with known supported/unsupported sender types and assert the boolean result, and call verify_context with valid and invalid contexts to assert Ok and Err(GatewayError::VerifyFailed(_)) outcomes; use EthGateway::new or ::with_base_fee to construct, and reference the methods register_payload_verifier, supports_sender_type, and verify_context so the tests validate the gateway-level wiring rather than only the registry unit tests.crates/app/tx/eth/src/mempool.rs (3)
498-501: Envelope decode usesbase_fee=0, affectingeffective_gas_price.When decoding a raw envelope (non-wire format),
base_fee=0is used (line 500). For EIP-1559 transactions, this affects the calculatedeffective_gas_price. If this is intentional (e.g., for replay/recovery where ordering doesn't matter), consider adding a brief comment.+ // Envelope-only decode path uses zero base fee; effective_gas_price + // is recalculated for mempool insertion in decode_and_verify. let envelope = TxEnvelope::decode(bytes)?; TxContext::new(envelope, 0).ok_or(ERR_RECIPIENT_REQUIRED)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@crates/app/tx/eth/src/mempool.rs` around lines 498 - 501, The TxEnvelope::decode + TxContext::new call currently constructs the TxContext with base_fee=0 which changes effective_gas_price calculation for EIP-1559 transactions; update the code near TxEnvelope::decode / TxContext::new to either compute/pass the correct base_fee derived from the envelope or (if zero is intentional for replay/recovery) add a concise comment explaining why base_fee=0 is used and the implication for effective_gas_price and ordering; reference TxEnvelope::decode, TxContext::new, effective_gas_price and ERR_RECIPIENT_REQUIRED when making the change so reviewers can quickly find and verify the intent.
330-336:recipient()returnsAccountId::invalid()forNoneresolution.When
recipient_resolutionisNone,recipient()returnsAccountId::invalid(). This sentinel value could propagate silently and cause subtle bugs if callers don't check for it.Consider whether this should panic (like
sender_address()) or whetherAccountId::invalid()is a well-defined sentinel that callers are expected to handle.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@crates/app/tx/eth/src/mempool.rs` around lines 330 - 336, The recipient() method currently returns AccountId::invalid() for RecipientResolution::None which can silently propagate; change it to mirror sender_address() behavior and fail loudly: replace the None branch to panic with a clear message (e.g. using panic! or expect on an Option) instead of returning AccountId::invalid(), so callers don't receive a silent sentinel; update the RecipientResolution::None handling in recipient() (and ensure any tests/call sites reflect the new panic semantics) while keeping the Account and EoaAddress branches using the existing account and derive_eth_eoa_account_id(address) logic.
236-243: Panic-based accessors may cause runtime failures.
sender_address()(line 240) andenvelope()(line 272) panic when called on incompatible payload types. While_optvariants exist, panics in library code can be surprising to callers.Consider either:
- Documenting these as
#[doc(hidden)]or internal-only- Returning
Resultinstead of panicking- Adding debug assertions in tests to catch misuse early
The current approach is acceptable if callers are expected to check
sender_type()orpayload()first, but the panic messages should be more actionable.Also applies to: 268-274
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@crates/app/tx/eth/src/mempool.rs` around lines 236 - 243, The accessor methods sender_address() and envelope() currently panic on incompatible SenderResolution/Payload types which can cause runtime failures; change them to return Result<T, Error> (e.g., Result<Address, MyError> / Result<EnvelopeType, MyError>) instead of panicking so callers must handle the mismatch, update call sites to propagate or handle the error, and add a clear, actionable error variant/message indicating the expected variant and the actual variant; alternatively, if these are truly internal-only, mark them #[doc(hidden)] and replace the panic text with a more descriptive message and/or add debug_assert! checks (but prefer the Result approach for public APIs).crates/app/tx/eth/src/verifier/registry.rs (1)
90-96: Backward-compatibleverifyallocates unnecessarily.The
verifymethod creates a newBoxallocation for every call viaBox::new(tx.clone()). For high-throughput scenarios, consider whether callers can migrate toverify_payloaddirectly.This is acceptable for a transitional compatibility shim, but the allocation overhead should be documented or the method marked as deprecated if migration is expected.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@crates/app/tx/eth/src/verifier/registry.rs` around lines 90 - 96, The compatibility shim register::verify currently allocates by cloning the TxEnvelope into a Box for every call (Box::new(tx.clone()) passed as TxPayload::Eoa) — mark this method as deprecated and document the allocation cost so callers migrate to verify_payload; specifically add a #[deprecated(...)] attribute to the verify function, update its doc comment to state it performs a heap allocation (via TxPayload::Eoa(Box::new(...))) and clearly recommend callers call verify_payload(sender_type::EOA_SECP256K1, &TxPayload::Eoa(...)) directly to avoid the clone/Box allocation.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@crates/rpc/evnode/src/service.rs`:
- Line 13: The import list in service.rs includes an unused symbol MempoolTx
from evolve_mempool; remove MempoolTx from the use statement (leave Mempool and
SharedMempool) so the compiler warning goes away and imports only used symbols;
update the line containing "use evolve_mempool::{Mempool, MempoolTx,
SharedMempool};" to exclude MempoolTx.
---
Nitpick comments:
In `@bin/testapp/tests/mempool_e2e.rs`:
- Around line 577-581: Ed25519AuthPayload is being constructed with a hardcoded
nonce (0); change the code to take the nonce from the transaction builder input
instead. Update the builder/input struct (Ed25519CustomTxBuildInput) to include
a nonce field if it doesn't exist, pass that input through to the test, and
replace the literal 0 with input.nonce when constructing auth_payload in the
test where Ed25519AuthPayload and auth_payload are created so multi-transaction
tests can supply different nonces.
- Around line 802-806: The local SignatureVerifierRegistry created here
(SignatureVerifierRegistry::new(), registry.register_dyn(sender_types::CUSTOM,
Ed25519PayloadVerifier), and the call to
registry.verify_payload(sender_types::CUSTOM, tx_context.payload())) is only
being used to test the verifier logic prior to submission and is not wired into
the STF/block execution path; add a concise comment above this block stating
that this registry is local to the test and that in production the verifier
registry must be configured and injected into the STF/gateway so the block
execution path uses the same verifiers.
- Around line 91-105: The error codes 0x71–0x74 in the functions
err_invalid_auth_payload, err_nonce_mismatch, err_invalid_public_key, and
err_invalid_signature collide with those used by Ed25519PayloadVerifier; change
these account-level error functions to return codes from a distinct,
non-overlapping range (e.g., bump to 0x80–0x83 or define an ACCOUNT_ERROR_BASE
constant) and update any tests/comments accordingly so verifier vs account
errors are unambiguous, or alternatively add a clear documented allocation
comment that reserves 0x71–0x74 for verifier errors and reassign account errors
to a different range.
- Around line 56-79: The verify implementation in Ed25519PayloadVerifier (impl
SignatureVerifierDyn for Ed25519PayloadVerifier -> fn verify) collapses multiple
failure modes into ErrorCode::new(0x75), hindering debugging; update each
failure site (the TxPayload match arm for TxPayload::Custom, both
borsh::from_slice calls for EthIntentPayload and Ed25519EthIntentProof,
intent.decode_envelope(), to_invoke_requests().next() missing-case, and
invoke_request.encode()) to return distinct ErrorCode values (e.g., 0x75..0x7A)
so callers can distinguish invalid payload type, intent decode error, auth_proof
decode error, envelope decode error, missing invoke request, and encode error
respectively; change the Err(...) and map_err(...) invocations to use the new
unique ErrorCode::new(...) values while keeping existing shapes and mapping
locations intact (match arm, borsh::from_slice map_err, decode_envelope map_err,
ok_or_else for next, encode map_err).
In `@crates/app/tx/eth/src/eoa_registry.rs`:
- Around line 185-213: The current branching in ensure_eoa_mapping is confusing
and can be simplified: first call lookup_account_id_in_env(address) and if
Some(existing) and existing != account_id return ERR_ADDRESS_ACCOUNT_CONFLICT;
then call lookup_address_in_env(account_id) and if Some(existing_addr) and
existing_addr != address return ERR_ADDRESS_ACCOUNT_CONFLICT; if both lookups
returned Some and they match return Ok(()); otherwise call set_mapping(address,
account_id, env). Update ensure_eoa_mapping to use lookup_account_id_in_env,
lookup_address_in_env, ERR_ADDRESS_ACCOUNT_CONFLICT, and set_mapping in that
order to make the logic linear and avoid the nested fall-through.
In `@crates/app/tx/eth/src/gateway.rs`:
- Around line 163-184: In verify_envelope, check the envelope chain ID against
self.chain_id before calling self.verifier.verify_payload so chain-id mismatches
return GatewayError::InvalidChainId deterministically; only if the chain ID
matches (or is absent if that’s acceptable) proceed to call verify_payload and
map its failure to GatewayError::InvalidSignature (or propagate the existing
mapping for None/Some mismatches handled earlier); keep the final
TxContext::new(envelope,
self.base_fee).ok_or(GatewayError::ContractCreationNotSupported) unchanged.
- Around line 187-218: Add integration tests in the existing tests module for
EthGateway that exercise the new public API: call register_payload_verifier on
an EthGateway instance to register a mock verifier and assert it is accepted
(and errors handled), call supports_sender_type with known supported/unsupported
sender types and assert the boolean result, and call verify_context with valid
and invalid contexts to assert Ok and Err(GatewayError::VerifyFailed(_))
outcomes; use EthGateway::new or ::with_base_fee to construct, and reference the
methods register_payload_verifier, supports_sender_type, and verify_context so
the tests validate the gateway-level wiring rather than only the registry unit
tests.
In `@crates/app/tx/eth/src/mempool.rs`:
- Around line 498-501: The TxEnvelope::decode + TxContext::new call currently
constructs the TxContext with base_fee=0 which changes effective_gas_price
calculation for EIP-1559 transactions; update the code near TxEnvelope::decode /
TxContext::new to either compute/pass the correct base_fee derived from the
envelope or (if zero is intentional for replay/recovery) add a concise comment
explaining why base_fee=0 is used and the implication for effective_gas_price
and ordering; reference TxEnvelope::decode, TxContext::new, effective_gas_price
and ERR_RECIPIENT_REQUIRED when making the change so reviewers can quickly find
and verify the intent.
- Around line 330-336: The recipient() method currently returns
AccountId::invalid() for RecipientResolution::None which can silently propagate;
change it to mirror sender_address() behavior and fail loudly: replace the None
branch to panic with a clear message (e.g. using panic! or expect on an Option)
instead of returning AccountId::invalid(), so callers don't receive a silent
sentinel; update the RecipientResolution::None handling in recipient() (and
ensure any tests/call sites reflect the new panic semantics) while keeping the
Account and EoaAddress branches using the existing account and
derive_eth_eoa_account_id(address) logic.
- Around line 236-243: The accessor methods sender_address() and envelope()
currently panic on incompatible SenderResolution/Payload types which can cause
runtime failures; change them to return Result<T, Error> (e.g., Result<Address,
MyError> / Result<EnvelopeType, MyError>) instead of panicking so callers must
handle the mismatch, update call sites to propagate or handle the error, and add
a clear, actionable error variant/message indicating the expected variant and
the actual variant; alternatively, if these are truly internal-only, mark them
#[doc(hidden)] and replace the panic text with a more descriptive message and/or
add debug_assert! checks (but prefer the Result approach for public APIs).
In `@crates/app/tx/eth/src/verifier/registry.rs`:
- Around line 90-96: The compatibility shim register::verify currently allocates
by cloning the TxEnvelope into a Box for every call (Box::new(tx.clone()) passed
as TxPayload::Eoa) — mark this method as deprecated and document the allocation
cost so callers migrate to verify_payload; specifically add a #[deprecated(...)]
attribute to the verify function, update its doc comment to state it performs a
heap allocation (via TxPayload::Eoa(Box::new(...))) and clearly recommend
callers call verify_payload(sender_type::EOA_SECP256K1, &TxPayload::Eoa(...))
directly to avoid the clone/Box allocation.
In `@docker-compose.testapp.yml`:
- Around line 2-26: Add a container healthcheck and restart policy to the
testapp service in docker-compose.testapp.yml: under the service named "testapp"
add a healthcheck that uses a CMD curl -f against http://localhost:8545 with
interval 10s, timeout 5s and retries 3, and set restart to "unless-stopped" so
the container is automatically restarted on transient failures; ensure these
keys are placed alongside existing "ports", "environment", and "volumes" entries
for the testapp service.
In `@docker/evd/Dockerfile`:
- Around line 9-12: The fallback RUN line using "rustup show active-toolchain ||
rustup toolchain install" won't install a specific toolchain; update it to
trigger auto-install from rust-toolchain.toml by replacing the fallback with a
single "rustup show" (which consults rust-toolchain.toml) or explicitly install
the channel parsed from rust-toolchain.toml; locate the COPY rust-toolchain.toml
./rust-toolchain.toml and the RUN rustup show active-toolchain || rustup
toolchain install lines and either call rustup show alone or extract the
"channel" from rust-toolchain.toml and pass it to rustup toolchain install so a
concrete toolchain is installed.
ℹ️ Review info
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (17)
bin/testapp/Cargo.tomlbin/testapp/tests/mempool_e2e.rscrates/app/sdk/stf_traits/src/lib.rscrates/app/stf/src/lib.rscrates/app/tx/eth/src/eoa_registry.rscrates/app/tx/eth/src/error.rscrates/app/tx/eth/src/gateway.rscrates/app/tx/eth/src/lib.rscrates/app/tx/eth/src/mempool.rscrates/app/tx/eth/src/payload.rscrates/app/tx/eth/src/sender_type.rscrates/app/tx/eth/src/verifier/mod.rscrates/app/tx/eth/src/verifier/registry.rscrates/rpc/chain-index/src/provider.rscrates/rpc/evnode/src/service.rsdocker-compose.testapp.ymldocker/evd/Dockerfile
| use evolve_core::encoding::{Decodable, Encodable}; | ||
| use evolve_core::ReadonlyKV; | ||
| use evolve_mempool::{Mempool, SharedMempool}; | ||
| use evolve_mempool::{Mempool, MempoolTx, SharedMempool}; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
rg -n 'MempoolTx' crates/rpc/evnode/src/service.rsRepository: evstack/ev-rs
Length of output: 116
Remove unused import MempoolTx.
MempoolTx is imported on line 13 but is not used anywhere in this file.
Fix
-use evolve_mempool::{Mempool, MempoolTx, SharedMempool};
+use evolve_mempool::{Mempool, SharedMempool};📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| use evolve_mempool::{Mempool, MempoolTx, SharedMempool}; | |
| use evolve_mempool::{Mempool, SharedMempool}; |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@crates/rpc/evnode/src/service.rs` at line 13, The import list in service.rs
includes an unused symbol MempoolTx from evolve_mempool; remove MempoolTx from
the use statement (leave Mempool and SharedMempool) so the compiler warning goes
away and imports only used symbols; update the line containing "use
evolve_mempool::{Mempool, MempoolTx, SharedMempool};" to exclude MempoolTx.
Overview
Design and implement a multi signature scheme system that allows users to migrate verification schemes of their accounts and chains can add thier own custom schemes
Summary by CodeRabbit
New Features
Refactor
Chores