From 7149cd646cca3807d12c09d3e4371f61f390fa49 Mon Sep 17 00:00:00 2001 From: gagliardetto Date: Tue, 25 Feb 2025 23:10:55 +0100 Subject: [PATCH 1/2] error parsing: add borsh io error --- solana-errors/from-json-to-protobuf.go | 44 +++++++++++----- solana-errors/from-json-to-protobuf_test.go | 57 +++++++++++++++++++-- solana-errors/solana-errors.go | 15 ++++++ 3 files changed, 100 insertions(+), 16 deletions(-) diff --git a/solana-errors/from-json-to-protobuf.go b/solana-errors/from-json-to-protobuf.go index 2714e890..4863874f 100644 --- a/solana-errors/from-json-to-protobuf.go +++ b/solana-errors/from-json-to-protobuf.go @@ -71,26 +71,46 @@ func FromJSONToProtobuf(j map[string]interface{}) ([]byte, error) { if firstKey == "" { return nil, fmt.Errorf("no keys found in map") } - if firstKey != "Custom" { + if firstKey != "Custom" && firstKey != "BorshIoError" { return nil, fmt.Errorf("expected a Custom key") } - doer.Do("write customErrorType", func() error { - return wr.WriteUint32(uint32(InstructionErrorType_CUSTOM), bin.LE) - }) - customErrorTypeFloat, ok := as[firstKey].(float64) - if !ok { - return nil, fmt.Errorf("expected a float64") + switch firstKey { + case "Custom": + { + doer.Do("write customErrorType", func() error { + return wr.WriteUint32(uint32(InstructionErrorType_CUSTOM), bin.LE) + }) + customErrorTypeFloat, ok := as[firstKey].(float64) + if !ok { + return nil, fmt.Errorf("expected a float64") + } + customErrorType := uint32(customErrorTypeFloat) + doer.Do("write customErrorType", func() error { + return wr.WriteUint32(customErrorType, bin.LE) + }) + } + case "BorshIoError": + { + doer.Do("write borshIoErrorType", func() error { + return wr.WriteUint32(uint32(InstructionErrorType_BORSH_IO_ERROR), bin.LE) + }) + // BorshIoError(String), + borshIoError, ok := as[firstKey].(string) + if !ok { + return nil, fmt.Errorf("expected a string") + } + doer.Do("write borshIoError", func() error { + return wr.WriteString(borshIoError) + }) + } + default: + return nil, fmt.Errorf("unhandled type %T", as) } - customErrorType := uint32(customErrorTypeFloat) - doer.Do("write customErrorType", func() error { - return wr.WriteUint32(customErrorType, bin.LE) - }) } default: return nil, fmt.Errorf("unhandled type %T", arr[1]) } } - } err := doer.Err() diff --git a/solana-errors/from-json-to-protobuf_test.go b/solana-errors/from-json-to-protobuf_test.go index 27ec1964..dcefffcc 100644 --- a/solana-errors/from-json-to-protobuf_test.go +++ b/solana-errors/from-json-to-protobuf_test.go @@ -26,10 +26,10 @@ func TestFromJSONToProtobuf(t *testing.T) { require.NotNil(t, buf) require.Equal(t, []byte{ - 0x8, 0x0, 0x0, 0x0, - 0x2, - 0x19, 0x0, 0x0, 0x0, - 0x71, 0x17, 0x0, 0x0, + 0x8, 0x0, 0x0, 0x0, // instruction error + 0x2, // error code + 0x19, 0x0, 0x0, 0x0, // instruction error type + 0x71, 0x17, 0x0, 0x0, // 6001 }, buf, ) @@ -51,6 +51,55 @@ func TestFromJSONToProtobuf(t *testing.T) { require.NoError(t, err) require.NotNil(t, got) + require.JSONEq(t, + toJson(t, candidate), + toJson(t, got), + ) + } + } + { + candidate := map[string]any{ + "InstructionError": []any{ + 0.0, + map[string]any{ + "BorshIoError": "Unknown", + }, + }, + } + buf, err := FromJSONToProtobuf( + candidate, + ) + require.NoError(t, err) + require.NotNil(t, buf) + require.Equal(t, + []byte{ + 0x8, 0x0, 0x0, 0x0, + 0x0, + 0x2c, 0x0, 0x0, 0x0, + 0x7, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, // "Unknown" + }, + buf, + ) + require.Equal(t, + concat( + uint32tobytes(uint32(TransactionErrorType_INSTRUCTION_ERROR)), + []byte{0x0}, + uint32tobytes(uint32(InstructionErrorType_BORSH_IO_ERROR)), + // length of "Unknown" + []byte{0x7}, + []byte("Unknown"), + ), + buf, + ) + { + candidateAsBase64 := base64.StdEncoding.EncodeToString(buf) + wrapped := map[string]any{ + "err": candidateAsBase64, + } + got, err := ParseTransactionError(wrapped) + require.NoError(t, err) + require.NotNil(t, got) + require.JSONEq(t, toJson(t, candidate), toJson(t, got), diff --git a/solana-errors/solana-errors.go b/solana-errors/solana-errors.go index d1009e5c..b6e8941b 100644 --- a/solana-errors/solana-errors.go +++ b/solana-errors/solana-errors.go @@ -289,6 +289,21 @@ func ParseTransactionError(v any) (map[string]any, error) { }, }, }, nil + case InstructionErrorType_BORSH_IO_ERROR: + borshIoError, err := dec.ReadString() + if err != nil { + return nil, err + } + return map[string]any{ + transactionErrorTypeName: []any{ + errorCode, + map[string]any{ + instructionErrorTypeName: borshIoError, + }, + }, + }, nil + default: + return nil, fmt.Errorf("unknown instruction error type: %d", instructionErrorType) } return map[string]any{ From 86cd72a728a0bf770b0382d9382878370d98eebd Mon Sep 17 00:00:00 2001 From: gagliardetto Date: Wed, 26 Feb 2025 12:07:12 +0100 Subject: [PATCH 2/2] Fix errors --- solana-errors/from-json-to-protobuf.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/solana-errors/from-json-to-protobuf.go b/solana-errors/from-json-to-protobuf.go index 4863874f..71cc01c3 100644 --- a/solana-errors/from-json-to-protobuf.go +++ b/solana-errors/from-json-to-protobuf.go @@ -72,7 +72,7 @@ func FromJSONToProtobuf(j map[string]interface{}) ([]byte, error) { return nil, fmt.Errorf("no keys found in map") } if firstKey != "Custom" && firstKey != "BorshIoError" { - return nil, fmt.Errorf("expected a Custom key") + return nil, fmt.Errorf("expected a Custom or BorshIoError key, got %q", firstKey) } switch firstKey { case "Custom": @@ -82,7 +82,7 @@ func FromJSONToProtobuf(j map[string]interface{}) ([]byte, error) { }) customErrorTypeFloat, ok := as[firstKey].(float64) if !ok { - return nil, fmt.Errorf("expected a float64") + return nil, fmt.Errorf("expected a float64, got %T", as[firstKey]) } customErrorType := uint32(customErrorTypeFloat) doer.Do("write customErrorType", func() error { @@ -97,7 +97,7 @@ func FromJSONToProtobuf(j map[string]interface{}) ([]byte, error) { // BorshIoError(String), borshIoError, ok := as[firstKey].(string) if !ok { - return nil, fmt.Errorf("expected a string") + return nil, fmt.Errorf("expected a string, got %T", as[firstKey]) } doer.Do("write borshIoError", func() error { return wr.WriteString(borshIoError)