英文:
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="
}
detail
和detail2
的输出结果如下:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论