Using default go XDR SafeUnmarshalBase64 function to decode TransactionEnvelope generates below EOF error if the XDR is not padded with ==
xdr:DecodeUint: unexpected EOF while decoding 4 bytes - read: '[0 0 0]'
Example code with and without padded ==
```package main
import (
"fmt"
"github.com/stellar/go/xdr"
)
func main() {
var tx xdr.TransactionEnvelope
// This will Fail as it is not padded with ==
err := xdr.SafeUnmarshalBase64("AAAAAAGUcmKO5465JxTSLQOQljwk2SfqAJmZSG6JH6wtqpwhAAAAZAAAAAAAAAACAAAAAQAAAAAAAAAAAAAAAF3cIOUAAAABAAAAG3JzbGt8TElvcUpCQkllTlFaTXpSTHZZVml2UgAAAAABAAAAAAAAAAYAAAACUEhPVE9OAAAAAAAAAAAAAGjEO6b/++00uc1YpgKQXsQsuNM06P8+taS0Fn6atJ53f/////////8AAAAAAAAAAA", &tx)
// This will work as it is padded with ==
// err := xdr.SafeUnmarshalBase64("AAAAAAGUcmKO5465JxTSLQOQljwk2SfqAJmZSG6JH6wtqpwhAAAAZAAAAAAAAAACAAAAAQAAAAAAAAAAAAAAAF3cIOUAAAABAAAAG3JzbGt8TElvcUpCQkllTlFaTXpSTHZZVml2UgAAAAABAAAAAAAAAAYAAAACUEhPVE9OAAAAAAAAAAAAAGjEO6b/++00uc1YpgKQXsQsuNM06P8+taS0Fn6atJ53f/////////8AAAAAAAAAAA==", &tx)
if err != nil {
fmt.Println(err)
}
}
```
Both of above XDR Transaction Envelope works fine on Stellar Laboratory XDR viewer
https://www.stellar.org/laboratory/#xdr-viewer
I expected no error in decoding TransactionEnvelope using default SafeUnmarshalBase64 function.
I saw the error - xdr:DecodeUint: unexpected EOF while decoding 4 bytes - read: '[0 0 0]' if XDR envelope is not padded with ==
It seems like a discrepancy between our SDKs. The js-sdk produces non-padded base64 encoding while the go sdk expects padding. Obviously, this is a problem.
There are various approaches we can take: all consumers don't expect padding, all producers produce padding, or both. But the main thing we need is parity between the SDKs.
@ire-and-curses thoughts?
@tomerweller In my uses of our js-stellar-sdk padding exists. e.g. https://jsfiddle.net/fgmb6254/1/. Where did you see it wasn't adding padding?
I think we need to have producers and consumers be consistent and that consistency should be to include padding to maximize backwards compatibility and make implementations straightforward. In [RFC4648] padding is really only mentioned as optional in specific situations which our use case doesn't fall into. Stellar-core internally uses padding on its base64 encoded data too. Some languages handle missing or unexpected padding gracefully. Javascript, Ruby and Java do, but not Go or Python. Not all languages have an implementation that supports generating base64 without padding either.
@aanupam23 can you share a jsfiddle that demonstrates how you ended up with an unpadded base64 string?
@leighmcculloch You are right about this, the JS is handling this gracefully and because of that this bug wasn't caught on keybase.
@tomerweller == was trimmed in the backend POC and application backend and couldn't get caught in testing since JS is gracefully handling this trimming. I agree with @leighmcculloch in regards to producers and consumer having consistency as this will improve backward compatibility and help in catching such bugs in early stages.
Thanks for all the support :)
Unfortunately I don't think we can, or should try to, do much about different platform Base 64 decoders being more or less strict. But we should continue to be consistent with how we encode XDR messages. I wrote up as brief-as-can-be statement about that here: stellar/stellar-protocol#487.
Just catching up to this. I agree with @leighmcculloch's analysis. We could improve consistency by making the JS etc more strict but this seems more annoying than it's worth.
Most helpful comment
@tomerweller In my uses of our js-stellar-sdk padding exists. e.g. https://jsfiddle.net/fgmb6254/1/. Where did you see it wasn't adding padding?
I think we need to have producers and consumers be consistent and that consistency should be to include padding to maximize backwards compatibility and make implementations straightforward. In [RFC4648] padding is really only mentioned as optional in specific situations which our use case doesn't fall into. Stellar-core internally uses padding on its base64 encoded data too. Some languages handle missing or unexpected padding gracefully. Javascript, Ruby and Java do, but not Go or Python. Not all languages have an implementation that supports generating base64 without padding either.