Skip to content

Commit 60ccd62

Browse files
fix(rpc): match ParsedTransactionMeta to TransactionMeta
Agave returns the same UiTransactionStatusMeta shape on the wire for both binary and jsonParsed encodings — only the innerInstructions[].instructions[] shape differs (compiled vs parsed, via an untagged serde enum). Our Go split into TransactionMeta / ParsedTransactionMeta dropped five trailing fields on the parsed side when the type was originally written, so a jsonParsed tx silently loses Status, Rewards, LoadedAddresses, ReturnData, and ComputeUnitsConsumed on decode. Mirror those five fields onto ParsedTransactionMeta. No new types needed — LoadedAddresses / ReturnData / DeprecatedTransactionMetaStatus already live in this file, and the remaining two are plain types. Adds TestParsedTransactionMeta_Decode as a regression guard: a realistic jsonParsed meta fixture with every previously-missing field populated, asserting each round-trips cleanly. Closes #284
1 parent 828ac78 commit 60ccd62

2 files changed

Lines changed: 72 additions & 0 deletions

File tree

rpc/types.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -543,6 +543,17 @@ type ParsedTransactionMeta struct {
543543
// Array of string log messages or omitted if log message
544544
// recording was not yet enabled during this transaction
545545
LogMessages []string `json:"logMessages"`
546+
547+
// DEPRECATED: Transaction status.
548+
Status DeprecatedTransactionMetaStatus `json:"status"`
549+
550+
Rewards []BlockReward `json:"rewards"`
551+
552+
LoadedAddresses LoadedAddresses `json:"loadedAddresses"`
553+
554+
ReturnData ReturnData `json:"returnData"`
555+
556+
ComputeUnitsConsumed *uint64 `json:"computeUnitsConsumed"`
546557
}
547558

548559
type ParsedInnerInstruction struct {

rpc/types_test.go

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,3 +113,64 @@ func TestData_DataBytesOrJSONFromBytes(t *testing.T) {
113113
out := dataBytesOrJSON.GetBinary()
114114
assert.Equal(t, in, out)
115115
}
116+
117+
// TestParsedTransactionMeta_Decode guards issue #284: the jsonParsed
118+
// and binary encodings return the same UiTransactionStatusMeta shape
119+
// on the wire, so every field on TransactionMeta must also decode
120+
// cleanly onto ParsedTransactionMeta. The fixture carries every trailing
121+
// field that was historically dropped (status, rewards, loadedAddresses,
122+
// returnData, computeUnitsConsumed) plus the parsed inner-instructions
123+
// shape that distinguishes this path from the binary one.
124+
func TestParsedTransactionMeta_Decode(t *testing.T) {
125+
in := []byte(`{
126+
"err": null,
127+
"fee": 5000,
128+
"preBalances": [1000000, 0],
129+
"postBalances": [994000, 1000],
130+
"innerInstructions": [{
131+
"index": 0,
132+
"instructions": [{
133+
"program": "system",
134+
"programId": "11111111111111111111111111111111",
135+
"parsed": {"type":"transfer","info":{"lamports":1}},
136+
"stackHeight": 1
137+
}]
138+
}],
139+
"preTokenBalances": [],
140+
"postTokenBalances": [],
141+
"logMessages": ["Program 11111111111111111111111111111111 invoke [1]"],
142+
"status": {"Ok": null},
143+
"rewards": [{
144+
"pubkey": "4ejjNYBbaETZyqaiK8aDj2BWER8LKHgDcCnRrPC22YGg",
145+
"lamports": 10,
146+
"postBalance": 1000010,
147+
"rewardType": "Fee"
148+
}],
149+
"loadedAddresses": {
150+
"writable": ["4ejjNYBbaETZyqaiK8aDj2BWER8LKHgDcCnRrPC22YGg"],
151+
"readonly": ["11111111111111111111111111111111"]
152+
},
153+
"returnData": {
154+
"programId": "11111111111111111111111111111111",
155+
"data": ["", "base64"]
156+
},
157+
"computeUnitsConsumed": 150
158+
}`)
159+
160+
var got ParsedTransactionMeta
161+
assert.NoError(t, stdjson.Unmarshal(in, &got))
162+
163+
assert.Equal(t, uint64(5000), got.Fee)
164+
assert.Len(t, got.InnerInstructions, 1)
165+
assert.Equal(t, "system", got.InnerInstructions[0].Instructions[0].Program)
166+
167+
// Fields that were missing before the #284 fix — regression guards.
168+
assert.Len(t, got.Rewards, 1)
169+
assert.Equal(t, int64(10), got.Rewards[0].Lamports)
170+
assert.Len(t, got.LoadedAddresses.Writable, 1)
171+
assert.Len(t, got.LoadedAddresses.ReadOnly, 1)
172+
assert.Equal(t, solana.MustPublicKeyFromBase58("11111111111111111111111111111111"), got.ReturnData.ProgramId)
173+
if assert.NotNil(t, got.ComputeUnitsConsumed) {
174+
assert.Equal(t, uint64(150), *got.ComputeUnitsConsumed)
175+
}
176+
}

0 commit comments

Comments
 (0)