Skip to content

Commit a3637b4

Browse files
author
Denis Ermolin
committed
refactor: use ExitPayloadReader for readability and typed txs
1 parent 29ceee3 commit a3637b4

File tree

2 files changed

+193
-34
lines changed

2 files changed

+193
-34
lines changed
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
pragma solidity ^0.8.0;
2+
3+
import { RLPReader } from "./RLPReader.sol";
4+
5+
library ExitPayloadReader {
6+
using RLPReader for bytes;
7+
using RLPReader for RLPReader.RLPItem;
8+
9+
uint8 constant WORD_SIZE = 32;
10+
11+
struct ExitPayload {
12+
RLPReader.RLPItem[] data;
13+
}
14+
15+
struct Receipt {
16+
RLPReader.RLPItem[] data;
17+
bytes raw;
18+
uint256 logIndex;
19+
}
20+
21+
struct Log {
22+
RLPReader.RLPItem data;
23+
RLPReader.RLPItem[] list;
24+
}
25+
26+
struct LogTopics {
27+
RLPReader.RLPItem[] data;
28+
}
29+
30+
// copy paste of private copy() from RLPReader to avoid changing of existing contracts
31+
function copy(uint src, uint dest, uint len) private pure {
32+
if (len == 0) return;
33+
34+
// copy as many word sizes as possible
35+
for (; len >= WORD_SIZE; len -= WORD_SIZE) {
36+
assembly {
37+
mstore(dest, mload(src))
38+
}
39+
40+
src += WORD_SIZE;
41+
dest += WORD_SIZE;
42+
}
43+
44+
// left over bytes. Mask is used to remove unwanted bytes from the word
45+
uint mask = 256 ** (WORD_SIZE - len) - 1;
46+
assembly {
47+
let srcpart := and(mload(src), not(mask)) // zero out src
48+
let destpart := and(mload(dest), mask) // retrieve the bytes
49+
mstore(dest, or(destpart, srcpart))
50+
}
51+
}
52+
53+
function toExitPayload(bytes memory data)
54+
internal
55+
pure
56+
returns (ExitPayload memory)
57+
{
58+
RLPReader.RLPItem[] memory payloadData = data
59+
.toRlpItem()
60+
.toList();
61+
62+
return ExitPayload(payloadData);
63+
}
64+
65+
function getHeaderNumber(ExitPayload memory payload) internal pure returns(uint256) {
66+
return payload.data[0].toUint();
67+
}
68+
69+
function getBlockProof(ExitPayload memory payload) internal pure returns(bytes memory) {
70+
return payload.data[1].toBytes();
71+
}
72+
73+
function getBlockNumber(ExitPayload memory payload) internal pure returns(uint256) {
74+
return payload.data[2].toUint();
75+
}
76+
77+
function getBlockTime(ExitPayload memory payload) internal pure returns(uint256) {
78+
return payload.data[3].toUint();
79+
}
80+
81+
function getTxRoot(ExitPayload memory payload) internal pure returns(bytes32) {
82+
return bytes32(payload.data[4].toUint());
83+
}
84+
85+
function getReceiptRoot(ExitPayload memory payload) internal pure returns(bytes32) {
86+
return bytes32(payload.data[5].toUint());
87+
}
88+
89+
function getReceipt(ExitPayload memory payload) internal pure returns(Receipt memory receipt) {
90+
receipt.raw = payload.data[6].toBytes();
91+
RLPReader.RLPItem memory receiptItem = receipt.raw.toRlpItem();
92+
93+
if (receiptItem.isList()) {
94+
// legacy tx
95+
receipt.data = receiptItem.toList();
96+
} else {
97+
// pop first byte before parsting receipt
98+
bytes memory typedBytes = receipt.raw;
99+
bytes memory result = new bytes(typedBytes.length - 1);
100+
uint256 srcPtr;
101+
uint256 destPtr;
102+
assembly {
103+
srcPtr := add(33, typedBytes)
104+
destPtr := add(0x20, result)
105+
}
106+
107+
copy(srcPtr, destPtr, result.length);
108+
receipt.data = result.toRlpItem().toList();
109+
}
110+
111+
receipt.logIndex = getReceiptLogIndex(payload);
112+
return receipt;
113+
}
114+
115+
function getReceiptProof(ExitPayload memory payload) internal pure returns(bytes memory) {
116+
return payload.data[7].toBytes();
117+
}
118+
119+
function getBranchMaskAsBytes(ExitPayload memory payload) internal pure returns(bytes memory) {
120+
return payload.data[8].toBytes();
121+
}
122+
123+
function getBranchMaskAsUint(ExitPayload memory payload) internal pure returns(uint256) {
124+
return payload.data[8].toUint();
125+
}
126+
127+
function getReceiptLogIndex(ExitPayload memory payload) internal pure returns(uint256) {
128+
return payload.data[9].toUint();
129+
}
130+
131+
// Receipt methods
132+
function toBytes(Receipt memory receipt) internal pure returns(bytes memory) {
133+
return receipt.raw;
134+
}
135+
136+
function getLog(Receipt memory receipt) internal pure returns(Log memory) {
137+
RLPReader.RLPItem memory logData = receipt.data[3].toList()[receipt.logIndex];
138+
return Log(logData, logData.toList());
139+
}
140+
141+
// Log methods
142+
function getEmitter(Log memory log) internal pure returns(address) {
143+
return RLPReader.toAddress(log.list[0]);
144+
}
145+
146+
function getTopics(Log memory log) internal pure returns(LogTopics memory) {
147+
return LogTopics(log.list[1].toList());
148+
}
149+
150+
function getData(Log memory log) internal pure returns(bytes memory) {
151+
return log.list[2].toBytes();
152+
}
153+
154+
function toRlpBytes(Log memory log) internal pure returns(bytes memory) {
155+
return log.data.toRlpBytes();
156+
}
157+
158+
// LogTopics methods
159+
function getField(LogTopics memory topics, uint256 index) internal pure returns(RLPReader.RLPItem memory) {
160+
return topics.data[index];
161+
}
162+
}

contracts/tunnel/FxBaseRootTunnel.sol

Lines changed: 31 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ pragma solidity ^0.8.0;
55
import {RLPReader} from "../lib/RLPReader.sol";
66
import {MerklePatriciaProof} from "../lib/MerklePatriciaProof.sol";
77
import {Merkle} from "../lib/Merkle.sol";
8+
import "../lib/ExitPayloadReader.sol";
89

910

1011
interface IFxStateSender {
@@ -28,9 +29,13 @@ contract ICheckpointManager {
2829
}
2930

3031
abstract contract FxBaseRootTunnel {
31-
using RLPReader for bytes;
3232
using RLPReader for RLPReader.RLPItem;
3333
using Merkle for bytes32;
34+
using ExitPayloadReader for bytes;
35+
using ExitPayloadReader for ExitPayloadReader.ExitPayload;
36+
using ExitPayloadReader for ExitPayloadReader.Log;
37+
using ExitPayloadReader for ExitPayloadReader.LogTopics;
38+
using ExitPayloadReader for ExitPayloadReader.Receipt;
3439

3540
// keccak256(MessageSent(bytes))
3641
bytes32 public constant SEND_MESSAGE_EVENT_SIG = 0x8c5261668696ce22758910d05bab8f186d6eb247ceac2af2e82c7dc17669b036;
@@ -69,20 +74,20 @@ abstract contract FxBaseRootTunnel {
6974
}
7075

7176
function _validateAndExtractMessage(bytes memory inputData) internal returns (bytes memory) {
72-
RLPReader.RLPItem[] memory inputDataRLPList = inputData
73-
.toRlpItem()
74-
.toList();
77+
ExitPayloadReader.ExitPayload memory payload = inputData.toExitPayload();
7578

79+
bytes memory branchMaskBytes = payload.getBranchMaskAsBytes();
80+
uint256 blockNumber = payload.getBlockNumber();
7681
// checking if exit has already been processed
7782
// unique exit is identified using hash of (blockNumber, branchMask, receiptLogIndex)
7883
bytes32 exitHash = keccak256(
7984
abi.encodePacked(
80-
inputDataRLPList[2].toUint(), // blockNumber
85+
blockNumber,
8186
// first 2 nibbles are dropped while generating nibble array
8287
// this allows branch masks that are valid but bypass exitHash check (changing first 2 nibbles only)
8388
// so converting to nibble array and then hashing it
84-
MerklePatriciaProof._getNibbleArray(inputDataRLPList[8].toBytes()), // branchMask
85-
inputDataRLPList[9].toUint() // receiptLogIndex
89+
MerklePatriciaProof._getNibbleArray(branchMaskBytes),
90+
payload.getReceiptLogIndex()
8691
)
8792
);
8893
require(
@@ -91,51 +96,43 @@ abstract contract FxBaseRootTunnel {
9196
);
9297
processedExits[exitHash] = true;
9398

94-
RLPReader.RLPItem[] memory receiptRLPList = inputDataRLPList[6]
95-
.toBytes()
96-
.toRlpItem()
97-
.toList();
98-
RLPReader.RLPItem memory logRLP = receiptRLPList[3]
99-
.toList()[
100-
inputDataRLPList[9].toUint() // receiptLogIndex
101-
];
102-
103-
RLPReader.RLPItem[] memory logRLPList = logRLP.toList();
104-
99+
ExitPayloadReader.Receipt memory receipt = payload.getReceipt();
100+
ExitPayloadReader.Log memory log = receipt.getLog();
101+
105102
// check child tunnel
106-
require(fxChildTunnel == RLPReader.toAddress(logRLPList[0]), "FxRootTunnel: INVALID_FX_CHILD_TUNNEL");
103+
require(fxChildTunnel == log.getEmitter(), "FxRootTunnel: INVALID_FX_CHILD_TUNNEL");
107104

105+
bytes32 receiptRoot = payload.getReceiptRoot();
108106
// verify receipt inclusion
109107
require(
110108
MerklePatriciaProof.verify(
111-
inputDataRLPList[6].toBytes(), // receipt
112-
inputDataRLPList[8].toBytes(), // branchMask
113-
inputDataRLPList[7].toBytes(), // receiptProof
114-
bytes32(inputDataRLPList[5].toUint()) // receiptRoot
109+
receipt.toBytes(),
110+
branchMaskBytes,
111+
payload.getReceiptProof(),
112+
receiptRoot
115113
),
116114
"FxRootTunnel: INVALID_RECEIPT_PROOF"
117115
);
118116

119117
// verify checkpoint inclusion
120118
_checkBlockMembershipInCheckpoint(
121-
inputDataRLPList[2].toUint(), // blockNumber
122-
inputDataRLPList[3].toUint(), // blockTime
123-
bytes32(inputDataRLPList[4].toUint()), // txRoot
124-
bytes32(inputDataRLPList[5].toUint()), // receiptRoot
125-
inputDataRLPList[0].toUint(), // headerNumber
126-
inputDataRLPList[1].toBytes() // blockProof
119+
blockNumber,
120+
payload.getBlockTime(),
121+
payload.getTxRoot(),
122+
receiptRoot,
123+
payload.getHeaderNumber(),
124+
payload.getBlockProof()
127125
);
128126

129-
RLPReader.RLPItem[] memory logTopicRLPList = logRLPList[1].toList(); // topics
127+
ExitPayloadReader.LogTopics memory topics = log.getTopics();
130128

131129
require(
132-
bytes32(logTopicRLPList[0].toUint()) == SEND_MESSAGE_EVENT_SIG, // topic0 is event sig
130+
bytes32(topics.getField(0).toUint()) == SEND_MESSAGE_EVENT_SIG, // topic0 is event sig
133131
"FxRootTunnel: INVALID_SIGNATURE"
134132
);
135133

136134
// received message data
137-
bytes memory receivedData = logRLPList[2].toBytes();
138-
(bytes memory message) = abi.decode(receivedData, (bytes)); // event decodes params again, so decoding bytes to get message
135+
(bytes memory message) = abi.decode(log.getData(), (bytes)); // event decodes params again, so decoding bytes to get message
139136
return message;
140137
}
141138

@@ -198,4 +195,4 @@ abstract contract FxBaseRootTunnel {
198195
* @param message bytes message that was sent from Child Tunnel
199196
*/
200197
function _processMessageFromChild(bytes memory message) virtual internal;
201-
}
198+
}

0 commit comments

Comments
 (0)