Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
122 changes: 116 additions & 6 deletions pkg/chains/stellar/proto_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -781,23 +781,103 @@ func ConvertGetTransactionRequestFromProto(p *GetTransactionRequest) (stellar.Ge
return stellar.GetTransactionRequest{TxHash: p.GetTxHash()}, nil
}

func ConvertGetTransactionResponseToProto(resp stellar.GetTransactionResponse) *GetTransactionResponse {
func ConvertGetTransactionResponseToProto(resp stellar.GetTransactionResponse) (*GetTransactionResponse, error) {
status, err := convertGetTransactionStatusToProto(resp.Status)
if err != nil {
return nil, err
}
if err := validateGetTransactionResponse(resp); err != nil {
return nil, err
}

var resultXDR, resultMetaXDR []byte
if resp.ResultXDR != "" {
resultXDR, err = base64.StdEncoding.DecodeString(resp.ResultXDR)
if err != nil {
return nil, fmt.Errorf("invalid result xdr %q: %w", resp.ResultXDR, err)
}
}
if resp.ResultMetaXDR != "" {
resultMetaXDR, err = base64.StdEncoding.DecodeString(resp.ResultMetaXDR)
if err != nil {
return nil, fmt.Errorf("invalid result meta xdr %q: %w", resp.ResultMetaXDR, err)
}
}

return &GetTransactionResponse{
Status: status,
TxHash: resp.TxHash,
ResultXdr: resultXDR,
ResultMetaXdr: resultMetaXDR,
FeeStroops: resp.FeeStroops,
LedgerSequence: resp.LedgerSequence,
LedgerCloseTime: resp.LedgerCloseTime,
}, nil
}

func validateGetTransactionResponse(resp stellar.GetTransactionResponse) error {
if resp.TxHash == "" {
return errors.New("txHash is required")
}

switch resp.Status {
case stellar.GetTransactionStatusNotFound:
switch {
case resp.FeeStroops != nil:
return errors.New("feeStroops must be unset when transaction is not found")
case resp.LedgerSequence != nil:
return errors.New("ledgerSequence must be unset when transaction is not found")
case resp.LedgerCloseTime != nil:
return errors.New("ledgerCloseTime must be unset when transaction is not found")
case resp.ResultXDR != "":
return errors.New("resultXDR must be empty when transaction is not found")
case resp.ResultMetaXDR != "":
return errors.New("resultMetaXDR must be empty when transaction is not found")
}
case stellar.GetTransactionStatusFailed, stellar.GetTransactionStatusSuccess:
switch {
case resp.LedgerSequence == nil:
return errors.New("ledgerSequence is required")
case resp.LedgerCloseTime == nil:
return errors.New("ledgerCloseTime is required")
case resp.ResultXDR == "":
return errors.New("resultXDR is required")
}
}
return nil
}

func ConvertGetTransactionResponseFromProto(p *GetTransactionResponse) (stellar.GetTransactionResponse, error) {
if p == nil {
return stellar.GetTransactionResponse{}, errors.New("get transaction response is nil")
}
return stellar.GetTransactionResponse{
FeeStroops: p.GetFeeStroops(),
LedgerSequence: p.GetLedgerSequence(),
LedgerCloseTime: p.GetLedgerCloseTime(),
}, nil
status, err := convertGetTransactionStatusFromProto(p.GetStatus())
if err != nil {
return stellar.GetTransactionResponse{}, fmt.Errorf("status: %w", err)
}

resp := stellar.GetTransactionResponse{
Status: status,
TxHash: p.GetTxHash(),
ResultXDR: base64.StdEncoding.EncodeToString(p.GetResultXdr()),
ResultMetaXDR: base64.StdEncoding.EncodeToString(p.GetResultMetaXdr()),
}
if p.FeeStroops != nil {
Comment thread
Krish-vemula marked this conversation as resolved.
fee := p.GetFeeStroops()
resp.FeeStroops = &fee
}
if p.LedgerSequence != nil {
ledger := p.GetLedgerSequence()
resp.LedgerSequence = &ledger
}
if p.LedgerCloseTime != nil {
closeTime := p.GetLedgerCloseTime()
resp.LedgerCloseTime = &closeTime
}
if err := validateGetTransactionResponse(resp); err != nil {
return stellar.GetTransactionResponse{}, err
}
return resp, nil
}

func ConvertGetSigningAccountResponseToProto(resp stellar.GetSigningAccountResponse) *GetSigningAccountResponse {
Expand Down Expand Up @@ -923,6 +1003,36 @@ func convertTxStatusFromProto(s TxStatus) (stellar.TransactionStatus, error) {
}
}

func convertGetTransactionStatusToProto(s stellar.GetTransactionStatus) (GetTransactionStatus, error) {
switch s {
case stellar.GetTransactionStatusUnspecified:
return 0, errors.New("get transaction status is required")
case stellar.GetTransactionStatusNotFound:
return GetTransactionStatus_GET_TRANSACTION_STATUS_NOT_FOUND, nil
case stellar.GetTransactionStatusFailed:
return GetTransactionStatus_GET_TRANSACTION_STATUS_FAILED, nil
case stellar.GetTransactionStatusSuccess:
return GetTransactionStatus_GET_TRANSACTION_STATUS_SUCCESS, nil
default:
return 0, fmt.Errorf("unsupported get transaction status: %d", s)
}
}
Comment thread
Copilot marked this conversation as resolved.

func convertGetTransactionStatusFromProto(s GetTransactionStatus) (stellar.GetTransactionStatus, error) {
switch s {
case GetTransactionStatus_GET_TRANSACTION_STATUS_UNSPECIFIED:
return 0, errors.New("get transaction status is required")
case GetTransactionStatus_GET_TRANSACTION_STATUS_NOT_FOUND:
return stellar.GetTransactionStatusNotFound, nil
case GetTransactionStatus_GET_TRANSACTION_STATUS_FAILED:
return stellar.GetTransactionStatusFailed, nil
case GetTransactionStatus_GET_TRANSACTION_STATUS_SUCCESS:
return stellar.GetTransactionStatusSuccess, nil
default:
return 0, fmt.Errorf("unsupported proto get transaction status: %d", s)
}
}

func scValsToProto(field string, vals []stellar.ScVal) ([]*scval.ScVal, error) {
if len(vals) == 0 {
return nil, nil
Expand Down
127 changes: 123 additions & 4 deletions pkg/chains/stellar/proto_helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1352,12 +1352,59 @@ func TestConvertGetTransactionRequestFromProto_EmptyTxHash(t *testing.T) {
}

func TestConvertGetTransactionResponse_RoundTrip(t *testing.T) {
fee := uint64(42)
ledger := uint32(100)
closeTime := int64(1_700_000_000)
domain := stellartypes.GetTransactionResponse{
FeeStroops: 42,
LedgerSequence: 100,
LedgerCloseTime: 1_700_000_000,
Status: stellartypes.GetTransactionStatusSuccess,
TxHash: "abc123hash",
ResultXDR: base64.StdEncoding.EncodeToString([]byte("result")),
ResultMetaXDR: base64.StdEncoding.EncodeToString([]byte("meta")),
FeeStroops: &fee,
LedgerSequence: &ledger,
LedgerCloseTime: &closeTime,
}
proto := conv.ConvertGetTransactionResponseToProto(domain)
proto, err := conv.ConvertGetTransactionResponseToProto(domain)
require.NoError(t, err)
require.Equal(t, conv.GetTransactionStatus_GET_TRANSACTION_STATUS_SUCCESS, proto.GetStatus())

got, err := conv.ConvertGetTransactionResponseFromProto(proto)
require.NoError(t, err)
require.Equal(t, domain, got)
}

func TestConvertGetTransactionResponse_RoundTrip_Failed(t *testing.T) {
ledger := uint32(100)
closeTime := int64(1_700_000_000)
domain := stellartypes.GetTransactionResponse{
Status: stellartypes.GetTransactionStatusFailed,
TxHash: "abc123hash",
ResultXDR: base64.StdEncoding.EncodeToString([]byte("failed-result")),
LedgerSequence: &ledger,
LedgerCloseTime: &closeTime,
}
proto, err := conv.ConvertGetTransactionResponseToProto(domain)
require.NoError(t, err)
require.Equal(t, conv.GetTransactionStatus_GET_TRANSACTION_STATUS_FAILED, proto.GetStatus())
require.Nil(t, proto.FeeStroops)

got, err := conv.ConvertGetTransactionResponseFromProto(proto)
require.NoError(t, err)
require.Equal(t, domain, got)
}

func TestConvertGetTransactionResponse_RoundTrip_NotFound(t *testing.T) {
domain := stellartypes.GetTransactionResponse{
Status: stellartypes.GetTransactionStatusNotFound,
TxHash: "abc123hash",
}
proto, err := conv.ConvertGetTransactionResponseToProto(domain)
require.NoError(t, err)
require.Equal(t, conv.GetTransactionStatus_GET_TRANSACTION_STATUS_NOT_FOUND, proto.GetStatus())
require.Nil(t, proto.FeeStroops)
require.Nil(t, proto.LedgerSequence)
require.Nil(t, proto.LedgerCloseTime)
require.Empty(t, proto.GetResultXdr())

got, err := conv.ConvertGetTransactionResponseFromProto(proto)
require.NoError(t, err)
Expand All @@ -1370,6 +1417,78 @@ func TestConvertGetTransactionResponseFromProto_Nil(t *testing.T) {
require.Contains(t, err.Error(), "nil")
}

func TestConvertGetTransactionResponseToProto_UnspecifiedStatus(t *testing.T) {
_, err := conv.ConvertGetTransactionResponseToProto(stellartypes.GetTransactionResponse{
TxHash: "abc123hash",
})
require.Error(t, err)
require.Contains(t, err.Error(), "status")
require.Contains(t, err.Error(), "get transaction status is required")
}

func TestConvertGetTransactionResponseToProto_UnsupportedStatus(t *testing.T) {
_, err := conv.ConvertGetTransactionResponseToProto(stellartypes.GetTransactionResponse{
Status: stellartypes.GetTransactionStatus(99),
TxHash: "abc123hash",
})
require.Error(t, err)
require.Contains(t, err.Error(), "status")
require.Contains(t, err.Error(), "unsupported get transaction status")
}

func TestConvertGetTransactionResponseFromProto_UnspecifiedStatus(t *testing.T) {
_, err := conv.ConvertGetTransactionResponseFromProto(&conv.GetTransactionResponse{
TxHash: "abc123hash",
})
require.Error(t, err)
require.Contains(t, err.Error(), "status")
require.Contains(t, err.Error(), "get transaction status is required")
}

func TestConvertGetTransactionResponseFromProto_UnsupportedStatus(t *testing.T) {
_, err := conv.ConvertGetTransactionResponseFromProto(&conv.GetTransactionResponse{
Status: conv.GetTransactionStatus(99),
TxHash: "abc123hash",
})
require.Error(t, err)
require.Contains(t, err.Error(), "status")
require.Contains(t, err.Error(), "unsupported proto get transaction status")
}

func TestConvertGetTransactionResponseToProto_SuccessMissingFields(t *testing.T) {
_, err := conv.ConvertGetTransactionResponseToProto(stellartypes.GetTransactionResponse{
Status: stellartypes.GetTransactionStatusSuccess,
TxHash: "abc123hash",
})
require.Error(t, err)
require.Contains(t, err.Error(), "ledgerSequence is required")
}

func TestConvertGetTransactionResponseFromProto_NotFoundWithFoundFields(t *testing.T) {
ledger := uint32(100)
_, err := conv.ConvertGetTransactionResponseFromProto(&conv.GetTransactionResponse{
Status: conv.GetTransactionStatus_GET_TRANSACTION_STATUS_NOT_FOUND,
TxHash: "abc123hash",
LedgerSequence: &ledger,
})
require.Error(t, err)
require.Contains(t, err.Error(), "ledgerSequence must be unset")
}

func TestConvertGetTransactionResponseToProto_InvalidResultXDR(t *testing.T) {
ledger := uint32(100)
closeTime := int64(1_700_000_000)
_, err := conv.ConvertGetTransactionResponseToProto(stellartypes.GetTransactionResponse{
Status: stellartypes.GetTransactionStatusSuccess,
TxHash: "abc123hash",
ResultXDR: "!!!invalid!!!",
LedgerSequence: &ledger,
LedgerCloseTime: &closeTime,
})
require.Error(t, err)
require.Contains(t, err.Error(), "invalid result xdr")
}

func TestConvertGetSigningAccountResponse_RoundTrip(t *testing.T) {
domain := stellartypes.GetSigningAccountResponse{AccountAddress: "GAAZI4TCR3TY5OJHCTJC2A4QSY6CJWJH5IAJTGKIN2ER7LBNVKOCCWN7"}
proto := conv.ConvertGetSigningAccountResponseToProto(domain)
Expand Down
Loading
Loading