-
Notifications
You must be signed in to change notification settings - Fork 157
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
Create a more compact TxOut using unpacked Word64s #2534
Conversation
d427b05
to
5729ea5
Compare
Whats all the bit twiddling is about? Is there any reason you can't use |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice. I realise we cannot use PackedBytes
(because that itself cannot be unpacked due to it being a multi-constructor type), but I think the code would be a little cleaner if we factored out a 4-word 28byte hash type (which would be single-constructor and thus unpackable). It'd give us the same representation, but would factor the code more concisely.
Humm I have another branch that tries to extract things into something like |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here are more detailed suggestions that I meant by my #2534 (comment)
go :: Hash (CC.ADDRHASH crypto) a -> (Word64, Word64, Word64, Word64) | ||
go h = case fmap fromIntegral (BS.unpack (hashToBytes h)) of | ||
[ b1, | ||
b2, | ||
b3, | ||
b4, | ||
b5, | ||
b6, | ||
b7, | ||
b8, | ||
b9, | ||
b10, | ||
b11, | ||
b12, | ||
b13, | ||
b14, | ||
b15, | ||
b16, | ||
b17, | ||
b18, | ||
b19, | ||
b20, | ||
b21, | ||
b22, | ||
b23, | ||
b24, | ||
b25, | ||
b26, | ||
b27, | ||
b28 | ||
] -> | ||
( toWord64 b1 b2 b3 b4 b5 b6 b7 b8, | ||
toWord64 b9 b10 b11 b12 b13 b14 b15 b16, | ||
toWord64 b17 b18 b19 b20 b21 b22 b23 b24, | ||
toWord64 b25 b26 b27 b28 0 0 0 (networkBit .&. payCredTypeBit) | ||
) | ||
_ -> error "Impossible! Wrong number of bytes" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By using PackedBytes
we can avoid creating an intermediate ByteString
and remove the need to convert hashes through lists and doing it byte-by-byte, all of which is much slower than it has to be.
go :: Hash (CC.ADDRHASH crypto) a -> (Word64, Word64, Word64, Word64) | |
go h = case fmap fromIntegral (BS.unpack (hashToBytes h)) of | |
[ b1, | |
b2, | |
b3, | |
b4, | |
b5, | |
b6, | |
b7, | |
b8, | |
b9, | |
b10, | |
b11, | |
b12, | |
b13, | |
b14, | |
b15, | |
b16, | |
b17, | |
b18, | |
b19, | |
b20, | |
b21, | |
b22, | |
b23, | |
b24, | |
b25, | |
b26, | |
b27, | |
b28 | |
] -> | |
( toWord64 b1 b2 b3 b4 b5 b6 b7 b8, | |
toWord64 b9 b10 b11 b12 b13 b14 b15 b16, | |
toWord64 b17 b18 b19 b20 b21 b22 b23 b24, | |
toWord64 b25 b26 b27 b28 0 0 0 (networkBit .&. payCredTypeBit) | |
) | |
_ -> error "Impossible! Wrong number of bytes" | |
go :: SizeHash (CC.ADDRHASH crypto) ~ 28 => Hash (CC.ADDRHASH crypto) a -> (Word64, Word64, Word64, Word64) | |
go h = | |
case hashToPackedBytes h of | |
PackedBytes28 a64 b64 c64 d32 -> (a64, b64, c64, (fromIntegral d32 `shiftL` 32) .|. fromIntegral (networkBit .&. payCredTypeBit)) | |
_ -> error "Impossible! Wrong number of bytes" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes! great suggestion. I'll do that. I think that .&.
is meant to be a .|.
I'll also elaborate on the error too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh yeah, you are right .&.
is meant to be .|.
. I was modifying your code when making the suggestion and didn't give that part much thought.
unsafeMakeSafeHash $ | ||
fromJust $ | ||
hashFromBytes $ | ||
BS.pack $ | ||
[ fromIntegral (w64 `shiftR` offset) | ||
| w64 <- [a, b, c, d], | ||
offset <- [56, 48 .. 0] | ||
] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here. Using lists in such a critical part of code for conversions of hash representation could have serious impact on performance. Also I recommend everyone to ban fromJust
from their vocabulary. Not only it is a partial function, but it also does not provide any information on the location of the failure, when it does happen (no matter how impossible it is)
unsafeMakeSafeHash $ | |
fromJust $ | |
hashFromBytes $ | |
BS.pack $ | |
[ fromIntegral (w64 `shiftR` offset) | |
| w64 <- [a, b, c, d], | |
offset <- [56, 48 .. 0] | |
] | |
hashFromPackedBytes (PackedBytes32 a b c d) |
encodeDataHash32 dataHash = case fmap fromIntegral (BS.unpack (hashToBytes (extractHash dataHash))) of | ||
[ b1, | ||
b2, | ||
b3, | ||
b4, | ||
b5, | ||
b6, | ||
b7, | ||
b8, | ||
b9, | ||
b10, | ||
b11, | ||
b12, | ||
b13, | ||
b14, | ||
b15, | ||
b16, | ||
b17, | ||
b18, | ||
b19, | ||
b20, | ||
b21, | ||
b22, | ||
b23, | ||
b24, | ||
b25, | ||
b26, | ||
b27, | ||
b28, | ||
b29, | ||
b30, | ||
b31, | ||
b32 | ||
] -> | ||
( toWord64 b1 b2 b3 b4 b5 b6 b7 b8, | ||
toWord64 b9 b10 b11 b12 b13 b14 b15 b16, | ||
toWord64 b17 b18 b19 b20 b21 b22 b23 b24, | ||
toWord64 b25 b26 b27 b28 b29 b30 b31 b32 | ||
) | ||
_ -> error "Impossible! Wrong number of bytes" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
encodeDataHash32 dataHash = case fmap fromIntegral (BS.unpack (hashToBytes (extractHash dataHash))) of | |
[ b1, | |
b2, | |
b3, | |
b4, | |
b5, | |
b6, | |
b7, | |
b8, | |
b9, | |
b10, | |
b11, | |
b12, | |
b13, | |
b14, | |
b15, | |
b16, | |
b17, | |
b18, | |
b19, | |
b20, | |
b21, | |
b22, | |
b23, | |
b24, | |
b25, | |
b26, | |
b27, | |
b28, | |
b29, | |
b30, | |
b31, | |
b32 | |
] -> | |
( toWord64 b1 b2 b3 b4 b5 b6 b7 b8, | |
toWord64 b9 b10 b11 b12 b13 b14 b15 b16, | |
toWord64 b17 b18 b19 b20 b21 b22 b23 b24, | |
toWord64 b25 b26 b27 b28 b29 b30 b31 b32 | |
) | |
_ -> error "Impossible! Wrong number of bytes" | |
encodeDataHash32 dataHash = | |
case hashToPackedBytes (extractHash dataHash) of | |
PackedBytes32 a b c d -> (a, b, c, d) |
import Data.Coders | ||
import Data.Maybe (fromMaybe) | ||
import Data.Maybe (fromJust, fromMaybe) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function along with other like head
, tail
, etc. should be banned in production code base
. It is better to use an explicit error
, because not only it is more descriptive, but it also provides a stack trace.
import Data.Maybe (fromJust, fromMaybe) | |
import Data.Maybe (fromMaybe) |
Here is a good example that I saw recently that depicts the problem very well: haskell/haskell-language-server#1618
_ -> error "Impossible! Wrong number of bytes" | ||
|
||
toWord64 :: Word8 -> Word8 -> Word8 -> Word8 -> Word8 -> Word8 -> Word8 -> Word8 -> Word64 | ||
toWord64 b1 b2 b3 b4 b5 b6 b7 b8 = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function can be removed with suggested changes in this review
43b5e30
to
0ec274f
Compare
0ec274f
to
1419b2a
Compare
7a7a3ef
to
00da965
Compare
@lehins after much fiddling with getting my gpg keys working, I've updated this PR with your suggestions. |
addrHash :: Hash (CC.ADDRHASH crypto) a | ||
addrHash = | ||
hashFromPackedBytes $ | ||
PackedBytes32 a b c (fromIntegral (d `shiftR` offset)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll be really surprised if this compiles. PackedBytes32
is a 32 byte hash constructor, but we are decoding an address with 28 bytes. Also offset
doesn't seem to be defined
Looks much better! 👍 However, there are still too many partial functions and some compilation errors that should be easy to fix. So, here is a challenge, it is possible to get rid of all partial functions from this PR, if you won't be able to get to it tomorrow I'll make a commit with the fix, I just don't have any more time to get to it today. |
00da965
to
813d175
Compare
In terms of partial functions there is I also have
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
I've special cased when the address hash size is 28 bytes and the data hash size is 32 bytes and the value is Ada only.
60fd847
to
47f2a81
Compare
I've special cased when the address hash size is 28 bytes and the data
hash size is 32 bytes and the value is Ada only.