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

Fix error conversion #180

Merged
merged 2 commits into from
Nov 14, 2024
Merged
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
255 changes: 171 additions & 84 deletions solana-errors/from-json-to-protobuf.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,108 +19,200 @@ func FromJSONToProtobuf(j map[string]interface{}) ([]byte, error) {
doer := &ChainOps{}
switch firstKey {
case InstructionError:
doer.Do("write transactionErrorType", func() error {
return wr.WriteUint32(uint32(TransactionErrorType_INSTRUCTION_ERROR), bin.LE)
})

{
// read instructionErrorType
arr, ok := j[InstructionError].([]interface{})
if !ok {
return nil, fmt.Errorf("expected an array")
}
if len(arr) != 2 {
return nil, fmt.Errorf("expected an array of length 2")
}
instructionErrorCodeFloat, ok := arr[0].(float64)
if !ok {
return nil, fmt.Errorf("expected a float64, got %T", arr[0])
}

instructionErrorCode := uint8(instructionErrorCodeFloat)
doer.Do("write errorCode", func() error {
return wr.WriteUint8(instructionErrorCode)
doer.Do("write transactionErrorType", func() error {
return wr.WriteUint32(uint32(TransactionErrorType_INSTRUCTION_ERROR), bin.LE)
})

{
switch as := arr[1].(type) {
case string:
{
// if string, then map instructionErrorTypeName to code
ixLoop:
for k, v := range InstructionErrorType_name {
// TODO: the conversion to PascalCase might be wrong and break things.
if bin.ToPascalCase(v) == as {
doer.Do("write instructionErrorType", func() error {
return wr.WriteUint32(uint32(k), bin.LE)
})
break ixLoop
// read instructionErrorType
arr, ok := j[InstructionError].([]interface{})
if !ok {
return nil, fmt.Errorf("expected an array")
}
if len(arr) != 2 {
return nil, fmt.Errorf("expected an array of length 2")
}
instructionErrorCodeFloat, ok := arr[0].(float64)
if !ok {
return nil, fmt.Errorf("expected a float64, got %T", arr[0])
}

instructionErrorCode := uint8(instructionErrorCodeFloat)
doer.Do("write errorCode", func() error {
return wr.WriteUint8(instructionErrorCode)
})

{
switch as := arr[1].(type) {
case string:
{
var found bool
// if string, then map instructionErrorTypeName to code
ixLoop:
for k, v := range InstructionErrorType_name {
// TODO: the conversion to PascalCase might be wrong and break things.
if bin.ToPascalCase(v) == as {
doer.Do("write instructionErrorType", func() error {
return wr.WriteUint32(uint32(k), bin.LE)
})
found = true
break ixLoop
}
}
if !found {
return nil, fmt.Errorf("unknown error type: %q", as)
}
}
}
case map[string]interface{}:
{
// if object, then it's custom
firstKey := getFirstKey(as)
if firstKey == "" {
return nil, fmt.Errorf("no keys found in map")
}
if firstKey != "Custom" {
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")
case map[string]interface{}:
{
// if object, then it's custom
firstKey := getFirstKey(as)
if firstKey == "" {
return nil, fmt.Errorf("no keys found in map")
}
if firstKey != "Custom" {
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")
}
customErrorType := uint32(customErrorTypeFloat)
doer.Do("write customErrorType", func() error {
return wr.WriteUint32(customErrorType, bin.LE)
})
}
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()
if err != nil {
return nil, err
}

err := doer.Err()
if err != nil {
return nil, err
return buf.Bytes(), nil
}

return buf.Bytes(), nil
case InsufficientFundsForRent:
doer.Do("write transactionErrorType", func() error {
return wr.WriteUint32(uint32(TransactionErrorType_INSUFFICIENT_FUNDS_FOR_RENT), bin.LE)
})
// write the accountIndex
{
// "{\"InsufficientFundsForRent\":{\"account_index\":2}}"
// read accountIndex
object, ok := j[InsufficientFundsForRent].(map[string]any)
if !ok {
return nil, fmt.Errorf("expected an object")
}
accountIndexFloat, ok := object["account_index"].(float64)
if !ok {
return nil, fmt.Errorf("expected a float64")
doer.Do("write transactionErrorType", func() error {
return wr.WriteUint32(uint32(TransactionErrorType_INSUFFICIENT_FUNDS_FOR_RENT), bin.LE)
})
// write the accountIndex
{
// "{\"InsufficientFundsForRent\":{\"account_index\":2}}"
// read accountIndex
object, ok := j[InsufficientFundsForRent].(map[string]any)
if !ok {
return nil, fmt.Errorf("expected an object")
}
accountIndexFloat, ok := object["account_index"].(float64)
if !ok {
return nil, fmt.Errorf("expected a float64")
}
accountIndex := uint8(accountIndexFloat)
doer.Do("write accountIndex", func() error {
return wr.WriteUint8(accountIndex)
})

if err := doer.Err(); err != nil {
return nil, err
}
}
accountIndex := uint8(accountIndexFloat)
doer.Do("write accountIndex", func() error {
return wr.WriteUint8(accountIndex)
return buf.Bytes(), nil
}
case ProgramExecutionTemporarilyRestricted:
{
doer.Do("write transactionErrorType", func() error {
return wr.WriteUint32(uint32(TransactionErrorType_PROGRAM_EXECUTION_TEMPORARILY_RESTRICTED), bin.LE)
})
// write the accountIndex
{
// "{\"ProgramExecutionTemporarilyRestricted\":{\"account_index\":2}}"
// read accountIndex
object, ok := j[ProgramExecutionTemporarilyRestricted].(map[string]any)
if !ok {
return nil, fmt.Errorf("expected an object")
}
accountIndexFloat, ok := object["account_index"].(float64)
if !ok {
return nil, fmt.Errorf("expected a float64")
}
accountIndex := uint8(accountIndexFloat)
doer.Do("write accountIndex", func() error {
return wr.WriteUint8(accountIndex)
})

if err := doer.Err(); err != nil {
return nil, err
if err := doer.Err(); err != nil {
return nil, err
}
}
return buf.Bytes(), nil
}
case DuplicateInstruction:
{
doer.Do("write transactionErrorType", func() error {
return wr.WriteUint32(uint32(TransactionErrorType_DUPLICATE_INSTRUCTION), bin.LE)
})
// write the instruction index
{
// "{\"DuplicateInstruction\":[2]}"
// read instructionIndex
arr, ok := j[DuplicateInstruction].([]interface{})
if !ok {
return nil, fmt.Errorf("expected an array")
}
if len(arr) != 1 {
return nil, fmt.Errorf("expected an array of length 1")
}
instructionIndexFloat, ok := arr[0].(float64)
if !ok {
return nil, fmt.Errorf("expected a float64")
}
instructionIndex := uint8(instructionIndexFloat)
doer.Do("write instructionIndex", func() error {
return wr.WriteUint8(instructionIndex)
})

return buf.Bytes(), nil
if err := doer.Err(); err != nil {
return nil, err
}
}
return buf.Bytes(), nil
}

default:
return nil, fmt.Errorf("unhandled error type: %s from %q", firstKey, toJsonString(j))
// it's one of the single-value errors
{
// iterate over TransactionErrorType_name and find the matching key
var found bool
for k, v := range TransactionErrorType_name {
if bin.ToPascalCase(v) == firstKey {
doer.Do("write transactionErrorType", func() error {
return wr.WriteUint32(uint32(k), bin.LE)
})
found = true
break
}
}
if !found {
return nil, fmt.Errorf("unknown error type: %q", firstKey)
}
}

err := doer.Err()
if err != nil {
return nil, err
}

return buf.Bytes(), nil
}
}

Expand All @@ -139,11 +231,6 @@ func getFirstKey(m map[string]interface{}) string {
return ""
}

const (
InstructionError = "InstructionError"
InsufficientFundsForRent = "InsufficientFundsForRent"
)

type ChainOps struct {
e error
}
Expand Down
Loading
Loading