Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rlp meltdown #476

Merged
merged 29 commits into from
Nov 29, 2019
Merged

Rlp meltdown #476

merged 29 commits into from
Nov 29, 2019

Conversation

kevsul
Copy link
Contributor

@kevsul kevsul commented Nov 22, 2019

Extra restrictions to RLP and tx decoding:

  • refactored RLPReader.sol yo remove duplicate code
  • RLPReader.toUint() treats leading zeros as invalid
  • RLPReader.toAddress() requires the item data to be exactly 20 bytes.
  • RLPReader.toBytes32() requires the item data to be exactly 32 bytes.
  • Transaction inputs must be bytes32
  • Transaction inputs cannot be empty (all zeros)
  • Transaction outputs cannot be empty (outputGuard == 0 AND amount == 0)
  • Transaction metadata must be bytes32


return Transaction({txType: txType, inputs: inputs, outputs: outputs, metaData: metaData});
}

function isOutputEmpty(PaymentOutputModel.Output memory output) internal pure returns (bool) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have some places that was treating amount == 0 as empty. Might worth take a looks and see if those places should change to be using this or not. Probably does not make sense to change but let double check.

https://github.com/omisego/plasma-contracts/blob/master/plasma_framework/contracts/src/exits/payment/controllers/PaymentStartStandardExit.sol#L168

https://github.com/omisego/plasma-contracts/blob/master/plasma_framework/contracts/src/exits/payment/controllers/PaymentProcessInFlightExit.sol#L208-L224

plasma_framework/contracts/src/utils/RLPReader.sol Outdated Show resolved Hide resolved
* @dev This function is dangerous !!! Ensure that the returned length is within the bounds of where memPtr points to.
* @param memPtr Pointer to the dynamic bytes array in memory
* @return The encoded RLPItem length
* @return The length of the RLPItem (including the length field) and the offset of the payload
Copy link
Contributor

@boolafish boolafish Nov 25, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should it be "including the offset"?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean the total length - length of the length field and the data

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah...just see offset is in the later part of the sentence

plasma_framework/contracts/src/utils/RLPReader.sol Outdated Show resolved Hide resolved
plasma_framework/contracts/src/utils/RLPReader.sol Outdated Show resolved Hide resolved
*/
function decodeItemLengthUnsafe(uint256 memPtr) internal pure returns (uint256) {
uint256 decodedItemLengthUnsafe;
function decodeLengthAndOffset(uint256 memPtr) internal pure returns (uint256, uint256) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we just pass in the RLPItem and also do the length check done in the RLP spec python example?

https://github.com/ethereum/wiki/wiki/RLP

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it easy to do it like that. In the python example they use string manipulation with substr and concatenation, but this isn't so easy in Solidity. Memory pointers seem to be a better fit.

Copy link
Contributor

@boolafish boolafish Nov 27, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh, I am not suggesting about the memory pointer part. But if just compare the two functions, the python example also has conditions like length > prefix - 0x80 in the branchings. If we pass in the RLPItem, I think we can use the item.len to match the logic in python.

Or are they actually different things?

Copy link
Contributor Author

@kevsul kevsul Nov 27, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They're different. In python length = len(input), but in Solidity you only have the length of the overall buffer. You don't get the length of each item item.len (until you decode it)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean, in python length is the length of the remainder of the buffer, which is not the same as the item.len.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okay, let me try to understand the assemblies again 😅

@boolafish
Copy link
Contributor

lol, it is so much "fun" to read the assemblies, ewwww

* @param tx An RLP-encoded transaction
* @return A decoded PaymentTransaction struct
*/
function decode(bytes memory tx) internal pure returns (PaymentTransactionModel.Transaction memory) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

my IDE argues about the tx variable

This declaration shadows a builtin symbol.

Copy link
Contributor Author

@kevsul kevsul Nov 27, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice catch, I wonder why sol linter isn't picking these up?

inputs[i] = input;
}

PaymentOutputModel.Output[] memory outputs = new PaymentOutputModel.Output[](rlpOutputs.length);
for (uint i = 0; i < rlpOutputs.length; i++) {
PaymentOutputModel.Output memory output = PaymentOutputModel.decode(rlpOutputs[i]);
require(output.outputType > 0, "Output type must not be 0");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1.) Why are the checks related to PaymentOutputModel not in decode?
2.) I think we concluded that the amount has be greater than 0?

Copy link
Contributor Author

@kevsul kevsul Nov 28, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1.) Why are the checks related to PaymentOutputModel not in decode?

PaymentOutputModel is going to be removed as part of refactor, will be in the next PR

Copy link
Contributor Author

@kevsul kevsul Nov 28, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2.) I think we concluded that the amount has be greater than 0?

OK

@thec00n thec00n self-requested a review November 28, 2019 04:13
@thec00n
Copy link
Contributor

thec00n commented Nov 28, 2019

@kevsul
Copy link
Contributor Author

kevsul commented Nov 28, 2019

Yep

Will be refactored.

Copy link
Contributor

@thec00n thec00n left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Made a few minor doc improvements: #490
Otherwise LGTM.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants