goblockchaingrpcprotocton

How to pass the data value from any type into a GRPC Protobuf struct in Golang?


I'm trying to parse the data from the ADNL lib by tonutils-go and deliver the data by GRPC.

The data I need is structured as

// struct from tonutils-go
type Transaction struct {
    _           Magic         `tlb:"$0111"`
    AccountAddr []byte        `tlb:"bits 256"`
    LT          uint64        `tlb:"## 64"`
    PrevTxHash  []byte        `tlb:"bits 256"`
    PrevTxLT    uint64        `tlb:"## 64"`
    Now         uint32        `tlb:"## 32"`
    OutMsgCount uint16        `tlb:"## 15"`
    OrigStatus  AccountStatus `tlb:"."`
    EndStatus   AccountStatus `tlb:"."`
    IO          struct {
        In  *Message      `tlb:"maybe ^"`
        Out *MessagesList `tlb:"maybe ^"`
    } `tlb:"^"`
    TotalFees   CurrencyCollection     `tlb:"."`
    StateUpdate HashUpdate             `tlb:"^"` // of Account
    Description TransactionDescription `tlb:"^"`

    // not in scheme, but will be filled based on request data for flexibility
    Hash []byte `tlb:"-"`
}

type TransactionDescription struct {
    Description any `tlb:"."`
}


type TransactionDescriptionOrdinary struct {
    _            Magic         `tlb:"$0000"`
    CreditFirst  bool          `tlb:"bool"`
    StoragePhase *StoragePhase `tlb:"maybe ."`
    CreditPhase  *CreditPhase  `tlb:"maybe ."`
    ComputePhase ComputePhase  `tlb:"."`
    ActionPhase  *ActionPhase  `tlb:"maybe ^"`
    Aborted      bool          `tlb:"bool"`
    BouncePhase  *BouncePhase  `tlb:"maybe ."`
    Destroyed    bool          `tlb:"bool"`
}

type ComputePhase struct {
    Phase any `tlb:"."`
}


type ComputePhaseVM struct {
    _                Magic `tlb:"$1"`
    Success          bool  `tlb:"bool"`
    MsgStateUsed     bool  `tlb:"bool"`
    AccountActivated bool  `tlb:"bool"`
    GasFees          Coins `tlb:"."`
    Details          struct {
        GasUsed          *big.Int `tlb:"var uint 7"`
        GasLimit         *big.Int `tlb:"var uint 7"`
        GasCredit        *big.Int `tlb:"maybe var uint 3"`
        Mode             int8     `tlb:"## 8"`
        ExitCode         int32    `tlb:"## 32"`
        ExitArg          *int32   `tlb:"maybe ## 32"`
        VMSteps          uint32   `tlb:"## 32"`
        VMInitStateHash  []byte   `tlb:"bits 256"`
        VMFinalStateHash []byte   `tlb:"bits 256"`
    } `tlb:"^"`
}

The protobuf of TxTest:

message TxTest {
   int32 exitCode = 1;
}

The data I want to parse is ExitCode and the code as following:

    list, err := api.ListTransactions(context.Background(), addr, 1, uint64(txInfo.TxLT), data)
    if err != nil {
        log.Printf("send err: %s", err.Error())
        return nil, err
    }
    for _, t := range list {
        a := t.Description.Description

        var result tlb.TransactionDescriptionOrdinary

        b, err := json.MarshalIndent(a, "", "  ")
        if err != nil {
            fmt.Println("error:", err)
        }
        json.Unmarshal([]byte(string(b)), &result)

        var computePhase tlb.ComputePhaseVM

        c, err := json.MarshalIndent(result.ComputePhase.Phase, "", "  ")
        if err != nil {
            fmt.Println("error:", err)
        }

        json.Unmarshal([]byte(string(c)), &computePhase)


        detail := &pb.TxTest{
            ExitCode: computePhase.Details.ExitCode,
        }
        detail2 := struct {
            ExitCode int32 `json:"exit_code"`
        }{
            ExitCode: computePhase.Details.ExitCode,
        }

        fmt.Printf("detail: %+v\n", detail)
        fmt.Printf("detail2: %+v\n", detail2)

    }

The data struct of one transaction is:

{
  "AccountAddr": "HYmM1/kK6GB2DLV3zVkIRyEpKoHRTF/jG8K7tTG91sQ=",
  "LT": 11898016000001,
  "PrevTxHash": "iKGjsxdT0gzIJXGNIlvxy0+a1gGEQDED4f7ZAJ9dlmc=",
  "PrevTxLT": 11897712000001,
  "Now": 1685602760,
  "OutMsgCount": 1,
  "OrigStatus": "ACTIVE",
  "EndStatus": "ACTIVE",
  "IO": {
    "In": {
      "MsgType": "EXTERNAL_IN",
      "Msg": {
        "SrcAddr": "NONE",
        "DstAddr": "EQAdiYzX-QroYHYMtXfNWQhHISkqgdFMX-Mbwru1Mb3WxN5D",
        "ImportFee": "0",
        "StateInit": null,
        "Body": {}
      }
    },
    "Out": {
      "List": {}
    }
  },
  "TotalFees": {
    "Coins": "22324812",
    "ExtraCurrencies": {}
  },
  "StateUpdate": {
    "OldHash": "WUkeXyOS8hsWyQYRLHPmJHpfMUSID8oDTAq6fY20pyQ=",
    "NewHash": "e8tn4cP4lAkFwvDcGc/VqBZ7lZeB4mhjMbRFE8rpsQA="
  },
  "Description": {
    "Description": {
      "CreditFirst": true,
      "StoragePhase": {
        "StorageFeesCollected": "484",
        "StorageFeesDue": null,
        "StatusChange": {
          "Type": "UNCHANGED"
        }
      },
      "CreditPhase": null,
      "ComputePhase": {
        "Phase": {
          "Success": true,
          "MsgStateUsed": false,
          "AccountActivated": false,
          "GasFees": "19862000",
          "Details": {
            "GasUsed": 19862,
            "GasLimit": 0,
            "GasCredit": 10000,
            "Mode": 0,
            "ExitCode": 0,
            "ExitArg": null,
            "VMSteps": 404,
            "VMInitStateHash": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
            "VMFinalStateHash": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="
          }
        }
      },
      "ActionPhase": {
        "Success": true,
        "Valid": true,
        "NoFunds": false,
        "StatusChange": {
          "Type": "UNCHANGED"
        },
        "TotalFwdFees": "1000000",
        "TotalActionFees": "333328",
        "ResultCode": 0,
        "ResultArg": null,
        "TotalActions": 1,
        "SpecActions": 0,
        "SkippedActions": 0,
        "MessagesCreated": 1,
        "ActionListHash": "Fkoo2xX9jU4YxTGJlrUjvaYrRWTrYHEBkUywUYg9AV4=",
        "TotalMsgSize": {
          "Cells": 1,
          "Bits": 697
        }
      },
      "Aborted": false,
      "BouncePhase": null,
      "Destroyed": false
    }
  },
  "Hash": "VMXfRKfIEtmAiHm3brTvhSkAidE1CkgRW8RQBVarJtQ="
}

and output of detail and detail2 are:

detail: 
detail2: {ExitCode:0}

My question is why the struct generated by protoc couldn't parse the exitCode from the transaction but the struct I defined could work well?

How can I inject the data into the struct TxTest which is generated by protoc, and let me transmit the data by GRPC?


Solution

  • Try this with an exit code value other than 0 and I'm guessing you'll get a different result.

    Have a look at your generated code. I believe what's happening is that fmt.Printf is calling the generated String() method for your proto struct, which uses the prototext package to print the contents of your message rather than the default Go struct printer.

    This is expected behavior for for proto3; there's no distinction between an int32 value of 0 and an empty field.