如何将任何类型的数据值传递到Golang中的GRPC Protobuf结构体中?

huangapple go评论90阅读模式
英文:

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

问题

我正在尝试通过tonutils-go库解析数据,并通过GRPC传递数据。

我需要解析的数据结构如下所示:

// 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:"^"` // 账户的哈希更新
	Description TransactionDescription `tlb:"^"`
	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:"^"`
}

TxTest的protobuf定义如下:

message TxTest {
   int32 exitCode = 1;
}

我想解析的数据是ExitCode,代码如下:

	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)

	}

一笔交易的数据结构如下:

{
  "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="
}

detaildetail2的输出结果如下:

detail: 
detail2: {ExitCode:0}

我的问题是为什么由protoc生成的结构体无法解析交易中的exitCode,而我自己定义的结构体可以正常工作?

我应该如何将数据注入到由protoc生成的TxTest结构体中,并通过GRPC传输数据?

英文:

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?

答案1

得分: 2

尝试使用退出代码值为0以外的值,我猜你会得到不同的结果。

看一下你生成的代码。我相信正在发生的是fmt.Printf调用了生成的proto结构体的String()方法,该方法使用prototext包来打印消息的内容,而不是默认的Go结构体打印器。

这是proto3预期行为;在proto3中,int32值为0和空字段之间没有区别。

英文:

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.

huangapple
  • 本文由 发表于 2023年6月3日 19:00:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/76395739.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定