Skip to content

Commit 7a241f6

Browse files
committed
fix(plasmaCash): add targetBlock to the transaction signed attributes
This security fix will prevent from stealing the money for all cases, where operator should include user block, but he did not. Not placing transaction on `targetBlock` automatically makes that transaction invalid. Nobody can can use it as a challenge transaction, because plasma root for `targetBlock` will not match. LIT-16
1 parent c6cf1fd commit 7a241f6

File tree

12 files changed

+326
-238
lines changed

12 files changed

+326
-238
lines changed

contracts/PlasmaCash.sol

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -125,24 +125,24 @@ contract PlasmaCash is Withdrawable, Operable {
125125
emit LogStartExit(msg.sender, _depositId, 0, finalAt);
126126
}
127127

128-
function startTxExit(bytes _txBytes, bytes _proof, bytes _signature, address _spender, uint256 _targetBlock)
128+
function startTxExit(bytes _txBytes, bytes _proof, bytes _signature, address _spender)
129129
public
130130
onlyWithBond
131131
payable {
132132

133133
Transaction.TX memory transaction = Transaction.createTransaction(_txBytes);
134-
validateProofSignaturesAndTxData(_txBytes, _proof, _signature, _spender, _targetBlock);
134+
validateProofSignaturesAndTxData(_txBytes, _proof, _signature, _spender);
135135

136-
require(exits[transaction.depositId][_targetBlock].finalAt == 0, "exit already exists");
136+
require(exits[transaction.depositId][transaction.targetBlock].finalAt == 0, "exit already exists");
137137

138138
Deposit storage depositPtr = deposits[transaction.depositId];
139139
require(depositPtr.amount > 0, "deposit not exists");
140140
require(transaction.newOwner == msg.sender, "you are not the owner");
141141

142142

143-
uint256 finalAt = createExitAndPriority(transaction.depositId, _targetBlock);
143+
uint256 finalAt = createExitAndPriority(transaction.depositId, transaction.targetBlock);
144144

145-
emit LogStartExit(msg.sender, transaction.depositId, _targetBlock, finalAt);
145+
emit LogStartExit(msg.sender, transaction.depositId, transaction.targetBlock, finalAt);
146146
}
147147

148148

@@ -156,7 +156,7 @@ contract PlasmaCash is Withdrawable, Operable {
156156
}
157157

158158

159-
function challengeExit(bytes _txBytes, bytes _proof, bytes _signature, uint256 _targetBlock)
159+
function challengeExit(bytes _txBytes, bytes _proof, bytes _signature)
160160
public {
161161

162162
Transaction.TX memory transaction = Transaction.createTransaction(_txBytes);
@@ -171,7 +171,7 @@ contract PlasmaCash is Withdrawable, Operable {
171171
// we will allow users to challenge exit even after challenge time, until someone finalize it
172172
// allow: require(exit.finalAt > block.timestamp, "exit is final, you can't challenge it");
173173

174-
validateProofSignaturesAndTxData(_txBytes, _proof, _signature, exitPtr.exitor, _targetBlock);
174+
validateProofSignaturesAndTxData(_txBytes, _proof, _signature, exitPtr.exitor);
175175

176176
exitPtr.invalid = true;
177177

@@ -181,18 +181,18 @@ contract PlasmaCash is Withdrawable, Operable {
181181
}
182182

183183

184-
function validateProofSignaturesAndTxData(bytes _txBytes, bytes _proof, bytes _signature, address _signer, uint256 _targetBlock)
184+
function validateProofSignaturesAndTxData(bytes _txBytes, bytes _proof, bytes _signature, address _signer)
185185
public
186186
view
187187
returns (bool) {
188188
Transaction.TX memory transaction = Transaction.createTransaction(_txBytes);
189189
require(transaction.prevTxBlockIndex < chainBlockIndex, "blockchain is the future, but your tx must be from the past");
190-
require(_targetBlock > transaction.prevTxBlockIndex, "invalid targetBlock/prevTxBlockIndex");
190+
require(transaction.targetBlock > transaction.prevTxBlockIndex, "invalid targetBlock/prevTxBlockIndex");
191191

192192
bytes32 hash = Transaction.hashTransaction(transaction);
193193

194194
require(transaction.newOwner != _signer, "preventing sending loop");
195-
require(_proof.verifyProof(blocks[_targetBlock].merkleRoot, hash, transaction.depositId), "MerkleProof.verifyProof() failed");
195+
require(_proof.verifyProof(blocks[transaction.targetBlock].merkleRoot, hash, transaction.depositId), "MerkleProof.verifyProof() failed");
196196
require(Transaction.checkSig(_signer, hash, _signature), "Transaction.checkSig() failed");
197197

198198
return true;
@@ -241,6 +241,7 @@ contract PlasmaCash is Withdrawable, Operable {
241241
}
242242

243243

244+
244245
// helpers methods - just for testing, can be removed for release
245246

246247

contracts/lib/Transaction.sol

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,20 @@ library Transaction {
1313
uint256 depositId;
1414
uint256 prevTxBlockIndex;
1515
address newOwner;
16+
uint256 targetBlock;
1617
}
1718

1819
/// @dev this is ETH prefix, so we can be sure, data was signed in EVM
1920
bytes constant ETH_PREFIX = "\x19Ethereum Signed Message:\n32";
2021

2122
function createTransaction(bytes rlp) internal pure returns (TX memory) {
2223
RLP.RLPItem[] memory txList = rlp.toRLPItem().toList();
23-
require(txList.length == 3, "txList.length == 3");
24+
require(txList.length == 4, "txList.length == 4");
2425
return TX({
2526
depositId: txList[0].toUint(),
2627
prevTxBlockIndex: txList[1].toUint(),
27-
newOwner: txList[2].toAddress()
28+
newOwner: txList[2].toAddress(),
29+
targetBlock: txList[3].toUint()
2830
});
2931
}
3032

@@ -36,6 +38,6 @@ library Transaction {
3638
internal
3739
pure
3840
returns (bytes32) {
39-
return keccak256(abi.encodePacked(_tx.depositId, _tx.prevTxBlockIndex, _tx.newOwner));
41+
return keccak256(abi.encodePacked(_tx.depositId, _tx.prevTxBlockIndex, _tx.newOwner, _tx.targetBlock));
4042
}
4143
}

0 commit comments

Comments
 (0)