Skip to content

Commit 1ce5286

Browse files
committed
Merge remote-tracking branch 'origin/master' into feat/dispute-kit-forest
2 parents c302740 + b70f8b2 commit 1ce5286

File tree

7 files changed

+2268
-1841
lines changed

7 files changed

+2268
-1841
lines changed

contracts/src/bridge/FastBridgeSenderToEthereum.sol

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ contract FastBridgeSenderToEthereum is SafeBridgeSenderToEthereum, IFastBridgeSe
8080

8181
ticketID = currentTicketID++;
8282

83-
(bytes32 messageHash, bytes memory messageData) = _encode(ticketID, _receiver, _calldata);
83+
(bytes32 messageHash, bytes memory messageData) = _encode(ticketID, block.number, _receiver, _calldata);
8484
emit OutgoingMessage(ticketID, block.number, _receiver, messageHash, messageData);
8585

8686
tickets[ticketID] = Ticket({messageHash: messageHash, blockNumber: block.number, sentSafe: false});
@@ -102,7 +102,7 @@ contract FastBridgeSenderToEthereum is SafeBridgeSenderToEthereum, IFastBridgeSe
102102
require(ticket.messageHash != 0, "Ticket does not exist.");
103103
require(ticket.sentSafe == false, "Ticket already sent safely.");
104104

105-
(bytes32 messageHash, bytes memory messageData) = _encode(_ticketID, _receiver, _calldata);
105+
(bytes32 messageHash, bytes memory messageData) = _encode(_ticketID, ticket.blockNumber, _receiver, _calldata);
106106
require(ticket.messageHash == messageHash, "Invalid message for ticketID.");
107107

108108
// Safe Bridge message envelope
@@ -132,13 +132,14 @@ contract FastBridgeSenderToEthereum is SafeBridgeSenderToEthereum, IFastBridgeSe
132132

133133
function _encode(
134134
uint256 _ticketID,
135+
uint256 _blockNumber,
135136
address _receiver,
136137
bytes memory _calldata
137-
) internal view returns (bytes32 messageHash, bytes memory messageData) {
138+
) internal pure returns (bytes32 messageHash, bytes memory messageData) {
138139
// Encode the receiver address with the function signature + arguments i.e calldata
139140
messageData = abi.encode(_receiver, _calldata);
140141

141142
// Compute the hash over the message header (ticketID, blockNumber) and body (data).
142-
messageHash = keccak256(abi.encode(_ticketID, block.number, messageData));
143+
messageHash = keccak256(abi.encode(_ticketID, _blockNumber, messageData));
143144
}
144145
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
/**
4+
* @authors: [@shotaronowhere]
5+
* @reviewers: []
6+
* @auditors: []
7+
* @bounties: []
8+
* @deployments: []
9+
*/
10+
11+
pragma solidity ^0.8.0;
12+
13+
/**
14+
* @title MerkleProof
15+
* @author Shotaro N. - <[email protected]>
16+
* @dev A set of funcitons to verify merkle proofs.
17+
*/
18+
contract MerkleProof {
19+
/** @dev Validates membership of leaf in merkle tree with merkle proof.
20+
* @param proof The merkle proof.
21+
* @param leaf The leaf to validate membership in merkle tree.
22+
* @param merkleRoot The root of the merkle tree.
23+
*/
24+
function validateProof(
25+
bytes32[] memory proof,
26+
bytes32 leaf,
27+
bytes32 merkleRoot
28+
) internal pure returns (bool) {
29+
return (merkleRoot == calculateRoot(proof, leaf));
30+
}
31+
32+
/** @dev Validates membership of leaf in merkle tree with merkle proof.
33+
* @param proof The merkle proof.
34+
* @param data The data to validate membership in merkle tree.
35+
* @param merkleRoot The root of the merkle tree.
36+
*/
37+
function validateProof(
38+
bytes32[] memory proof,
39+
bytes memory data,
40+
bytes32 merkleRoot
41+
) public pure returns (bool) {
42+
return validateProof(proof, sha256(data), merkleRoot);
43+
}
44+
45+
/** @dev Calculates merkle root from proof.
46+
* @param proof The merkle proof.
47+
* @param leaf The leaf to validate membership in merkle tree..
48+
*/
49+
function calculateRoot(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {
50+
uint256 proofLength = proof.length;
51+
require(proofLength <= 64, "Invalid Proof");
52+
bytes32 h = leaf;
53+
for (uint256 i = 0; i < proofLength; i++) {
54+
bytes32 proofElement = proof[i];
55+
// effecient hash
56+
if (proofElement > h)
57+
assembly {
58+
mstore(0x00, h)
59+
mstore(0x20, proofElement)
60+
h := keccak256(0x00, 0x40)
61+
}
62+
else
63+
assembly {
64+
mstore(0x00, proofElement)
65+
mstore(0x20, h)
66+
h := keccak256(0x00, 0x40)
67+
}
68+
}
69+
return h;
70+
}
71+
}
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
/**
4+
* @authors: [@shotaronowhere]
5+
* @reviewers: []
6+
* @auditors: []
7+
* @bounties: []
8+
* @deployments: []
9+
*/
10+
11+
pragma solidity ^0.8.0;
12+
13+
/**
14+
* @title MerkleTreeHistory
15+
* @author Shotaro N. - <[email protected]>
16+
* @dev An efficient append only merkle tree with history.
17+
*/
18+
contract MerkleTreeHistory {
19+
// ***************************** //
20+
// * Storage * //
21+
// ***************************** //
22+
23+
// merkle tree representation
24+
// supports 2^64 messages.
25+
bytes32[64] public branch;
26+
uint256 public count;
27+
28+
// block number => merkle root history
29+
mapping(uint256 => bytes32) private history;
30+
31+
// ************************************* //
32+
// * State Modifiers * //
33+
// ************************************* //
34+
35+
/** @dev Append data into merkle tree.
36+
* `O(log(n))` where
37+
* `n` is the number of leaves.
38+
* Note: Although each insertion is O(log(n)),
39+
* Complexity of n insertions is O(n).
40+
* @param data The data to insert in the merkle tree.
41+
*/
42+
function append(bytes memory data) public {
43+
// Differentiate leaves from interior nodes with different
44+
// hash functions to prevent 2nd order pre-image attack.
45+
// https://flawed.net.nz/2018/02/21/attacking-merkle-trees-with-a-second-preimage-attack/
46+
bytes32 leaf = sha256(data);
47+
uint256 size = count + 1;
48+
count = size;
49+
uint256 hashBitField = (size ^ (size - 1)) & size;
50+
uint256 height;
51+
while ((hashBitField & 1) == 0) {
52+
bytes32 node = branch[height];
53+
if (node > leaf)
54+
assembly {
55+
// effecient hash
56+
mstore(0x00, leaf)
57+
mstore(0x20, node)
58+
leaf := keccak256(0x00, 0x40)
59+
}
60+
else
61+
assembly {
62+
// effecient hash
63+
mstore(0x00, node)
64+
mstore(0x20, leaf)
65+
leaf := keccak256(0x00, 0x40)
66+
}
67+
hashBitField /= 2;
68+
height = height + 1;
69+
}
70+
branch[height] = leaf;
71+
}
72+
73+
/** @dev Saves the merkle root state in history and resets.
74+
* `O(log(n))` where
75+
* `n` is the number of leaves.
76+
*/
77+
function reset() internal {
78+
history[block.number] = getMerkleRoot();
79+
count = 0;
80+
}
81+
82+
/** @dev Gets the merkle root history
83+
* `O(log(n))` where
84+
* `n` is the number of leaves.
85+
* @param blocknumber requested blocknumber.
86+
*/
87+
function getMerkleRootHistory(uint256 blocknumber) public view returns (bytes32) {
88+
if (blocknumber == block.number) return getMerkleRoot();
89+
90+
return history[blocknumber];
91+
}
92+
93+
/** @dev Gets the current merkle root.
94+
* `O(log(n))` where
95+
* `n` is the number of leaves.
96+
*/
97+
function getMerkleRoot() public view returns (bytes32) {
98+
bytes32 node;
99+
uint256 size = count;
100+
uint256 height = 0;
101+
bool isFirstHash = true;
102+
while (size > 0) {
103+
if ((size & 1) == 1) {
104+
// avoid redundant calculation
105+
if (isFirstHash) {
106+
node = branch[height];
107+
isFirstHash = false;
108+
} else {
109+
bytes32 hash = branch[height];
110+
// effecient hash
111+
if (hash > node)
112+
assembly {
113+
mstore(0x00, node)
114+
mstore(0x20, hash)
115+
node := keccak256(0x00, 0x40)
116+
}
117+
else
118+
assembly {
119+
mstore(0x00, hash)
120+
mstore(0x20, node)
121+
node := keccak256(0x00, 0x40)
122+
}
123+
}
124+
}
125+
size /= 2;
126+
height++;
127+
}
128+
return node;
129+
}
130+
}

0 commit comments

Comments
 (0)