RLP Encoding#2
Conversation
…ion and changing how RLPList are created
|
Are the protocol messages supposed to extend RLPValue? How about going more decoupled way, maybe something like json encoders/decoders (typeclasses) in Play! framework (and "clean" message classes)? |
|
Ditto on that. And while on implicits, why do we need the implicit conversion in the other directions, i.e. |
| * - so 56 and 2^64 space seems like the right place to put the cutoff | ||
| * - also, that's where Bitcoin's varint does the cutof | ||
| */ | ||
| val SIZE_THRESHOLD: Int = 56 |
There was a problem hiding this comment.
Do you think we could use the naming conventions as proposed here: http://docs.scala-lang.org/style/naming-conventions.html#constants-values-variable-and-methods? That is upper camel case.
| * <p> | ||
| * See: https://github.com/ethereum/wiki/wiki/%5BEnglish%5D-RLP | ||
| * | ||
| * @author Roman Mandeleil |
There was a problem hiding this comment.
lol....we wanted to keep main comments to help other to compare this impl against EtehereumJ but this one is a mistake...fixed!
| libraryDependencies ++= Seq( | ||
| "org.scorexfoundation" %% "scorex-core" % "2.0.0-M3", | ||
| "com.madgag.spongycastle" % "core" % "1.54.0.0", | ||
| "org.scalatest" %% "scalatest" % "2.+" % "test", |
There was a problem hiding this comment.
Let's use the newest testing libs
|
@LukasGasior1 about:
Ok, we will take a second look at it. We first tried type classes but the code got dirty very quickly. Feel free to point us some example / code regarding this if you want to. @rtkaczyk not sure if I understand:
You need that in order to decode messages to known types (for example this PingMessage example) |
|
@AlanVerbner then you can just have encode (and decode) method: capable of encoding any T as long as there's implicit encoder in scope // edit: @rtkaczyk ^ does that make sense? |
|
@LukasGasior1 yes, that's also what I was thinking. |
| case p if p <= OffsetLongItem => | ||
| val length = p - OffsetShortItem | ||
| val res: Array[Byte] = new Array[Byte](length) | ||
| Array.copy(data, pos + 1, res, 0, length) |
There was a problem hiding this comment.
maybe we can use ByteString here to to slice consecutive parts from data?
maybe than we could omit position and only pass reminder to recurrent call, sth. like:
val (res, remaining) = data.splitAt(length) ?
simmilar in other cases bellow
There was a problem hiding this comment.
@adamsmo Just pushed a version with ByteString. Tried different alternatives but finally decided not to "commit position and only pass reminder to recurrent call". That suggestion was in terms of speed or code clarity?
There was a problem hiding this comment.
@AlanVerbner thanks
it was about code clarity and readability
auto correct changed omit to commit
There was a problem hiding this comment.
@adamsmo it seems it works a little bit slower going for the omit position alternative (about 10-20%, I can run better tests to be more precise if you want to). I would vote to keep it as it is assuming the code is not too unreadable and we won't need to dig/touch this code too much. What do you think?
There was a problem hiding this comment.
@AlanVerbner sure let leave it as it is now, if this approach is more efficient
|
@LukasGasior1 @rtkaczyk Just pushed the improvements you suggested. Please let us know what do you think 😄 |
|
@AlanVerbner I think that's a step in good direction :) It seems RLPImplicits are not really implicits ATM: it would be way better if we could just write: this should be easily doable |
|
Ok, will take another look @LukasGasior1 😄 |
|
@LukasGasior1 I guess it's done now 😄 |
f85bea8 to
a878332
Compare
|
For the protocol handshake (frame codec actually) I'm also going to need following RLP-related methods (from ethereumj): and something like: see: @AlanVerbner |
|
@LukasGasior1 checking it atm |
|
@LukasGasior1 about @Test
public void partialDataParseTest() {
String hex = "000080c180000000000000000000000042699b1104e93abf0008be55f912c2ff";
RLPList el = (RLPList) decode2OneItem(Hex.decode(hex), 3);
assertEquals(1, el.size());
assertEquals(0, Util.rlpDecodeInt(el.get(0)));
}will be translated as: test("Partial Data Parse Test") {
val hex: String = "000080c180000000000000000000000042699b1104e93abf0008be55f912c2ff"
val data = Hex.decode(hex)
val decoded: Try[Seq[Int]] = RLP.decode[Seq[Int]](data.splitAt(3)._2)
assert(decoded.isSuccess)
assert(1 == decoded.get.length)
assert(0 == decoded.get.head)
}We can change the method signature in order to avoid doing the split before calling the rlp decoder you can call something like val decoded: Try[Seq[Int]] = RLP.decode[Seq[Int]](data, 3)That being said, it's important to note that our implementation does not support decoding arrays made like |
|
@AlanVerbner Sure it does. Didn't know it already works that way :) No need to change the signature, |
|
@LukasGasior1 |
|
Thanks, hopefully that will be all we need on rlp side :) |
|
@LukasGasior1 Sorry for the delay but tests were messing around with me. I've just pushed Please check if it fits networking needs. Also let me know if you want me to create tests for encoding / decoding handshake massages. |
|
Thanks, LGTM 👍 |
…ivate. Also method descriptions where added.
|
@AlanVerbner Can you, if you didn't already add tests for the 2 fixes you mention? Ta! |
|
@mcsherrylabs I've already did but will try to add a couple more if those are needed |
LukasGasior1
left a comment
There was a problem hiding this comment.
Beside unresolved conflict in build.sbt the changes look good to me 👍
| } | ||
| } | ||
|
|
||
| trait RLPValue extends RLPEncodeable { |
There was a problem hiding this comment.
why not just use case classes RLPValue(bytes) and similar for list?
// edit: see my comment at the bottom
There was a problem hiding this comment.
@LukasGasior1 let me see. I think it was left after a refactor and might be changed to case classes as you say.
| } | ||
| } | ||
|
|
||
| implicit def byteArrayToRLPValue(srcByteArray: Array[Byte]): RLPValue = new RLPValue { |
There was a problem hiding this comment.
this seems like it could be easily changed to accept Array[RLPEncodable] or even Iterable[RLPEncodable]
| case 1 => (bytes(0) & 0xFF).toByte | ||
| case _ => throw new Exception("src doesn't represent a byte") | ||
| } | ||
| case _ => throw new Exception("src is not an RLPValue") |
There was a problem hiding this comment.
if only RLPValue is supported then that's what should be the method's argument
| case 2 => (((bytes(0) & 0xFF) << 8) + (bytes(1) & 0xFF)).toShort | ||
| case _ => throw new Exception("src doesn't represent a short") | ||
| } | ||
| case _ => throw new Exception("src is not an RLPValue") |
There was a problem hiding this comment.
same as above (and below)
Add pending tx subscription; Ref #CGKIELE-632
Description
This PR includes a RLP binary encoding scala implementation.
As EthereumJ, RubyRLP, and PyRLP tests there might be some "duplicated" tests that we can remove sometime in the future but we wanted to keep them to make it easier for us to compare it against other implementations.
Also, you will find some "real life" encoding decoding examples (like an encoded by EthereumJ Ping Message decoding or a sample Block with TX composition).