跨合约调用无法获取值:Quorum与Parity下的Solidity合约问题
Hey there, let's break down why your testModifier function isn't returning a value on Quorum and Parity even though it works perfectly on Remix. I've looked through your code and setup, so here are the most likely culprits and fixes:
1. String Type Encoding Differences Across Clients
Solidity's string is a dynamic-length type, and while Remix uses standard ABI encoding, older versions of Parity and Quorum (built on Geth with privacy features) sometimes handle dynamic strings differently. Your contracts rely heavily on string for mapping keys and function parameters—this is probably the main issue.
2. Node Configuration Restrictions
Quorum and Parity nodes might have specific settings that block view function calls or restrict cross-contract access:
- Quorum: If you're using privacy features, your
Basecontract might not be authorized to read data from theUserRolecontract. Double-check if your contracts are marked as private and adjust permissions if needed. - Parity: Ensure your node's
--rpc-apiflag includesethandweb3(required for contract interactions) and that CORS settings allow your client to connect.
3. A Minor Logic Gap (Not the Root Cause, But Worth Fixing)
Quick note on your isAuthorized modifier: right now it hardcodes role = 5 and doesn't actually check the user's real role from UserRole. If you intended to validate the user's actual role against the <10 condition, update it like this:
modifier isAuthorized(string _username) { uint8 role = userRole.getRole(_username); // Fetch the real user role require(role < 10); _; }
This doesn't cause your return value issue, but it's a logical oversight worth addressing.
Fixes to Try
Swap string for bytes32
Dynamic strings are the most likely culprit here. Switching to fixed-length bytes32 eliminates encoding inconsistencies across clients. Here's how to adjust your contracts:
Updated UserRole Contract:
pragma solidity ^0.4.24; contract UserRole { address owner; mapping (bytes32 => uint8) userRoles; constructor() public { owner = msg.sender; } function set(bytes32 _username, uint8 _role) public returns (bool success) { userRoles[_username] = _role; return true; } function getRole(bytes32 _username) public view returns (uint8 _role) { return userRoles[_username]; } }
Updated Base Contract:
pragma solidity ^0.4.24; // Interface for UserRole to avoid full contract import interface UserRole { function getRole(bytes32 _username) public view returns (uint8); } contract Base { address owner; UserRole userRole; address public userRoleAddress; constructor(address _t) public { owner = msg.sender; userRoleAddress = _t; userRole = UserRole(_t); } modifier isAuthorized(bytes32 _username) { uint8 role = userRole.getRole(_username); require(role < 10); _; } function testModifier(bytes32 _username) public isAuthorized(_username) view returns (uint8 result) { return userRole.getRole(_username); } }
When calling the functions, convert your username to bytes32 (e.g., in web3.js: web3.utils.fromAscii("jamesbond")).
Verify Node Settings
- For Quorum: Disable privacy features temporarily to test if that's blocking access. If you need privacy, ensure
Baseis added to the privacy group ofUserRole. - For Parity: Check that your node allows external calls to view functions. Run your node with
--rpc-api eth,web3,personaland verify CORS is set to accept your client's origin.
Test with Static Calls
Use a static call to explicitly read the view function's return value, which avoids any transaction-related issues. In web3.js:
const baseContract = new web3.eth.Contract(baseAbi, baseContractAddress); const result = await baseContract.methods.testModifier(web3.utils.fromAscii("jamesbond")).call({ from: yourWalletAddress }); console.log("Returned role:", result);
内容的提问来源于stack exchange,提问作者shresthaal

