diff --git a/packages/protocol/contracts/signal/SignalService.sol b/packages/protocol/contracts/signal/SignalService.sol index a6685dd7f9..2281146c11 100644 --- a/packages/protocol/contracts/signal/SignalService.sol +++ b/packages/protocol/contracts/signal/SignalService.sol @@ -39,12 +39,15 @@ contract SignalService is EssentialContract, ISignalService { bytes[] storageProof; } - uint256[50] private __gap; + mapping(address => bool) public isRelayerAuthorized; + uint256[49] private __gap; event SnippetRelayed( uint64 indexed chainid, bytes32 indexed kind, bytes32 data, bytes32 signal ); + event RelayerAuthorized(address indexed addr, bool authrized); + error SS_EMPTY_PROOF(); error SS_INVALID_APP(); error SS_INVALID_LAST_HOP_CHAINID(); @@ -52,6 +55,7 @@ contract SignalService is EssentialContract, ISignalService { error SS_INVALID_PARAMS(); error SS_INVALID_SIGNAL(); error SS_LOCAL_CHAIN_DATA_NOT_FOUND(); + error SS_UNAUTHORIZED(); error SS_UNSUPPORTED(); /// @dev Initializer to be called after being deployed behind a proxy. @@ -59,6 +63,15 @@ contract SignalService is EssentialContract, ISignalService { __Essential_init(_addressManager); } + /// @dev Authorize or deautohrize an address for calling relayChainData + /// @dev Note that addr is supposed to be TaikoL1 and TaikoL1 contracts deployed locally. + function authorizeRelayer(address addr, bool toAuthorize) external onlyOwner { + if (isRelayerAuthorized[addr] == toAuthorize) revert SS_INVALID_PARAMS(); + isRelayerAuthorized[addr] = toAuthorize; + + emit RelayerAuthorized(addr, toAuthorize); + } + /// @inheritdoc ISignalService function relayChainData( uint64 chainId, @@ -66,9 +79,9 @@ contract SignalService is EssentialContract, ISignalService { bytes32 data ) external - onlyFromNamed("taiko") returns (bytes32 slot) { + if (!isRelayerAuthorized[msg.sender]) revert SS_UNAUTHORIZED(); return _relayChainData(chainId, kind, data); } diff --git a/packages/protocol/script/DeployOnL1.s.sol b/packages/protocol/script/DeployOnL1.s.sol index 748cc181fc..ab9dd07750 100644 --- a/packages/protocol/script/DeployOnL1.s.sol +++ b/packages/protocol/script/DeployOnL1.s.sol @@ -91,6 +91,10 @@ contract DeployOnL1 is DeployCapability { addressNotNull(taikoL1Addr, "taikoL1Addr"); TaikoL1 taikoL1 = TaikoL1(payable(taikoL1Addr)); + if (vm.envAddress("SHARED_ADDRESS_MANAGER") == address(0)) { + SignalService(signalServiceAddr).authorizeRelayer(taikoL1Addr, true); + } + uint64 l2ChainId = taikoL1.getConfig().chainId; require(l2ChainId != block.chainid, "same chainid"); @@ -116,7 +120,6 @@ contract DeployOnL1 is DeployCapability { copyRegister(rollupAddressManager, sharedAddressManager, "taiko_token"); copyRegister(rollupAddressManager, sharedAddressManager, "signal_service"); copyRegister(rollupAddressManager, sharedAddressManager, "bridge"); - copyRegister(sharedAddressManager, rollupAddressManager, "taiko"); address proposer = vm.envAddress("PROPOSER"); if (proposer != address(0)) { diff --git a/packages/protocol/test/L1/TaikoL1TestBase.sol b/packages/protocol/test/L1/TaikoL1TestBase.sol index eb8ade7288..6156dd54c2 100644 --- a/packages/protocol/test/L1/TaikoL1TestBase.sol +++ b/packages/protocol/test/L1/TaikoL1TestBase.sol @@ -54,6 +54,7 @@ abstract contract TaikoL1TestBase is TaikoTest { data: abi.encodeCall(SignalService.init, address(addressManager)) }) ); + ss.authorizeRelayer(address(L1), true); pv = PseZkVerifier( deployProxy({ diff --git a/packages/protocol/test/L2/TaikoL2.t.sol b/packages/protocol/test/L2/TaikoL2.t.sol index 8f8dd5a9d2..d53fcd0727 100644 --- a/packages/protocol/test/L2/TaikoL2.t.sol +++ b/packages/protocol/test/L2/TaikoL2.t.sol @@ -28,13 +28,15 @@ contract TestTaikoL2 is TaikoTest { data: abi.encodeCall(AddressManager.init, ()) }); - deployProxy({ - name: "signal_service", - impl: address(new SignalService()), - data: abi.encodeCall(SignalService.init, (addressManager)), - registerTo: addressManager, - owner: address(0) - }); + SignalService ss = SignalService( + deployProxy({ + name: "signal_service", + impl: address(new SignalService()), + data: abi.encodeCall(SignalService.init, (addressManager)), + registerTo: addressManager, + owner: address(0) + }) + ); uint64 gasExcess = 0; uint8 quotient = 8; @@ -55,6 +57,8 @@ contract TestTaikoL2 is TaikoTest { L2.setConfigAndExcess(TaikoL2.Config(gasTarget, quotient), gasExcess); + ss.authorizeRelayer(address(L2), true); + gasExcess = 195_420_300_100; vm.roll(block.number + 1); diff --git a/packages/protocol/test/L2/TaikoL2NoFeeCheck.t.sol b/packages/protocol/test/L2/TaikoL2NoFeeCheck.t.sol index 062b34afe7..777eeff035 100644 --- a/packages/protocol/test/L2/TaikoL2NoFeeCheck.t.sol +++ b/packages/protocol/test/L2/TaikoL2NoFeeCheck.t.sol @@ -27,13 +27,15 @@ contract TestTaikoL2NoFeeCheck is TaikoTest { data: abi.encodeCall(AddressManager.init, ()) }); - deployProxy({ - name: "signal_service", - impl: address(new SignalService()), - data: abi.encodeCall(SignalService.init, (addressManager)), - registerTo: addressManager, - owner: address(0) - }); + SignalService ss = SignalService( + deployProxy({ + name: "signal_service", + impl: address(new SignalService()), + data: abi.encodeCall(SignalService.init, (addressManager)), + registerTo: addressManager, + owner: address(0) + }) + ); uint64 gasExcess = 0; uint8 quotient = 8; @@ -55,6 +57,8 @@ contract TestTaikoL2NoFeeCheck is TaikoTest { L2.setConfigAndExcess(TaikoL2.Config(gasTarget, quotient), gasExcess); + ss.authorizeRelayer(address(L2), true); + vm.roll(block.number + 1); vm.warp(block.timestamp + 30); } diff --git a/packages/protocol/test/signal/SignalService.t.sol b/packages/protocol/test/signal/SignalService.t.sol index 3a3983fb2e..b029240a50 100644 --- a/packages/protocol/test/signal/SignalService.t.sol +++ b/packages/protocol/test/signal/SignalService.t.sol @@ -51,7 +51,7 @@ contract TestSignalService is TaikoTest { ); taiko = randAddress(); - addressManager.setAddress(uint64(block.chainid), "taiko", taiko); + signalService.authorizeRelayer(taiko, true); vm.stopPrank(); } @@ -298,6 +298,13 @@ contract TestSignalService is TaikoTest { signal: randBytes32(), proof: abi.encode(proofs) }); + + vm.prank(Alice); + signalService.authorizeRelayer(taiko, false); + + vm.expectRevert(SignalService.SS_UNAUTHORIZED.selector); + vm.prank(taiko); + signalService.relayChainData(srcChainId, LibSignals.SIGNAL_ROOT, proofs[0].rootHash); } function test_SignalService_proveSignalReceived_one_hop_state_root() public { diff --git a/packages/protocol/utils/generate_genesis/taikoL2.ts b/packages/protocol/utils/generate_genesis/taikoL2.ts index 3e2854e242..c351ffa957 100644 --- a/packages/protocol/utils/generate_genesis/taikoL2.ts +++ b/packages/protocol/utils/generate_genesis/taikoL2.ts @@ -242,9 +242,6 @@ async function generateContractConfigs( // AddressManager addresses: { [chainId]: { - [ethers.utils.hexlify( - ethers.utils.toUtf8Bytes("taiko"), - )]: addressMap.TaikoL2, [ethers.utils.hexlify( ethers.utils.toUtf8Bytes("bridge"), )]: addressMap.Bridge, @@ -464,6 +461,9 @@ async function generateContractConfigs( _owner: ownerSecurityCouncil, // AddressResolver addressManager: addressMap.SharedAddressManager, + isRelayerAuthorized: { + [addressMap.TaikoL2]: true, + }, }, slots: { [IMPLEMENTATION_SLOT]: addressMap.SignalServiceImpl,