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

Correctly omit transactionData field when transaction simulation fails #271

Merged
merged 9 commits into from
Aug 28, 2024
12 changes: 8 additions & 4 deletions cmd/soroban-rpc/internal/xdr2json/conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,28 +27,32 @@ import (
// and returns the raw JSON-formatted serialization of that object.
// It can be unmarshalled to a proper JSON structure, but the raw bytes are
// returned to avoid unnecessary round-trips. If there is an
// error, it returns an empty JSON object.
// error, it returns an empty string.
//
// The `xdr` object does not need to actually be initialized/valid:
// we only use it to determine the name of the structure. We could just
// accept a string, but that would make mistakes likelier than passing the
// structure itself (by reference).
func ConvertBytes(xdr interface{}, field []byte) ([]byte, error) {
func ConvertBytes(xdr interface{}, field []byte) (json.RawMessage, error) {
if len(field) == 0 {
return []byte(""), nil
}

xdrTypeName := reflect.TypeOf(xdr).Name()
return convertAnyBytes(xdrTypeName, field)
}

// ConvertInterface takes a valid XDR object (`xdr`) and returns
// the raw JSON-formatted serialization of that object. If there is an
// error, it returns an empty JSON object.
// error, it returns an empty string.
//
// Unlike `ConvertBytes`, the value here needs to be valid and
// serializable.
func ConvertInterface(xdr encoding.BinaryMarshaler) (json.RawMessage, error) {
xdrTypeName := reflect.TypeOf(xdr).Name()
data, err := xdr.MarshalBinary()
if err != nil {
return []byte("{}"), errors.Wrapf(err, "failed to serialize XDR type '%s'", xdrTypeName)
return []byte(""), errors.Wrapf(err, "failed to serialize XDR type '%s'", xdrTypeName)
}

return convertAnyBytes(xdrTypeName, data)
Expand Down
47 changes: 47 additions & 0 deletions cmd/soroban-rpc/internal/xdr2json/conversion_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package xdr2json

import (
"encoding/json"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/stellar/go/keypair"
"github.com/stellar/go/xdr"
)

func TestConversion(t *testing.T) {
// Make a structure to encode
pubkey := keypair.MustRandom()
asset := xdr.MustNewCreditAsset("ABCD", pubkey.Address())

// Try the all-inclusive version
jsi, err := ConvertInterface(asset)
require.NoError(t, err)

// Try the byte-and-interface version
rawBytes, err := asset.MarshalBinary()
require.NoError(t, err)
jsb, err := ConvertBytes(xdr.Asset{}, rawBytes)
require.NoError(t, err)

for _, rawJs := range []json.RawMessage{jsi, jsb} {
var dest map[string]interface{}
require.NoError(t, json.Unmarshal(rawJs, &dest))

require.Contains(t, dest, "credit_alphanum4")
require.Contains(t, dest["credit_alphanum4"], "asset_code")
require.Contains(t, dest["credit_alphanum4"], "issuer")
require.IsType(t, map[string]interface{}{}, dest["credit_alphanum4"])
if converted, ok := dest["credit_alphanum4"].(map[string]interface{}); assert.True(t, ok) {
require.Equal(t, pubkey.Address(), converted["issuer"])
}
}
}

func TestEmptyConversion(t *testing.T) {
js, err := ConvertBytes(xdr.SorobanTransactionData{}, []byte{})
require.NoError(t, err)
require.Equal(t, "", string(js))
}
10 changes: 8 additions & 2 deletions cmd/soroban-rpc/lib/xdr2json/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,18 @@ pub unsafe extern "C" fn xdr_to_json(
) -> *mut ConversionResult {
let result = catch_json_to_xdr_panic(Box::new(move || {
let type_str = unsafe { from_c_string(typename) };
let the_type = xdr::TypeVariant::from_str(&type_str).unwrap();
let the_type = match xdr::TypeVariant::from_str(&type_str) {
Ok(t) => t,
Err(e) => panic!("couldn't match type {type_str}: {}", e),
};

let xdr_bytearray = unsafe { from_c_xdr(xdr) };
let mut buffer = xdr::Limited::new(xdr_bytearray.as_slice(), DEFAULT_XDR_RW_LIMITS.clone());

let t = xdr::Type::read_xdr_to_end(the_type, &mut buffer).unwrap();
let t = match xdr::Type::read_xdr_to_end(the_type, &mut buffer) {
Ok(t) => t,
Err(e) => panic!("couldn't read {type_str}: {}", e),
Shaptic marked this conversation as resolved.
Show resolved Hide resolved
};

Ok(RustConversionResult {
json: serde_json::to_string(&t).unwrap(),
Expand Down
Loading