Skip to content

Commit 48975d7

Browse files
fix: actualize simulate transaction
1 parent 801a013 commit 48975d7

2 files changed

Lines changed: 206 additions & 1 deletion

File tree

rpc/client_test.go

Lines changed: 157 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2648,7 +2648,163 @@ func TestClient_IsBlockhashValid(t *testing.T) {
26482648
}
26492649

26502650
func TestClient_SimulateTransaction(t *testing.T) {
2651-
// TODO
2651+
responseBody := `{"context":{"slot":218},"value":{"accounts":null,"logs":["Program 83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri invoke [1]","Program 83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri consumed 2366 of 1400000 compute units","Program return: 83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri KgAAAAAAAAA=","Program 83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri success"],"unitsConsumed":2366}}`
2652+
server, closer := mockJSONRPC(t, stdjson.RawMessage(wrapIntoRPC(responseBody)))
2653+
defer closer()
2654+
client := New(server.URL)
2655+
2656+
txData := []byte{1, 2, 3, 4} // dummy transaction data
2657+
out, err := client.SimulateRawTransactionWithOpts(
2658+
context.Background(),
2659+
txData,
2660+
nil,
2661+
)
2662+
require.NoError(t, err)
2663+
2664+
assert.Nil(t, out.Value.Err)
2665+
assert.Len(t, out.Value.Logs, 4)
2666+
assert.Equal(t, uint64(2366), *out.Value.UnitsConsumed)
2667+
2668+
reqBody := server.RequestBody(t)
2669+
assert.NotNil(t, reqBody["id"])
2670+
reqBody["id"] = any(nil)
2671+
2672+
assert.Equal(t,
2673+
map[string]any{
2674+
"id": any(nil),
2675+
"jsonrpc": "2.0",
2676+
"method": "simulateTransaction",
2677+
"params": []any{
2678+
base64.StdEncoding.EncodeToString(txData),
2679+
map[string]any{
2680+
"encoding": "base64",
2681+
},
2682+
},
2683+
},
2684+
reqBody,
2685+
)
2686+
2687+
expected := mustJSONToInterface([]byte(responseBody))
2688+
got := mustJSONToInterface(mustAnyToJSON(out))
2689+
assert.Equal(t, expected, got, "both deserialized values must be equal")
2690+
}
2691+
2692+
func TestClient_SimulateTransactionWithOpts_AllOptions(t *testing.T) {
2693+
responseBody := `{"context":{"slot":218},"value":{"err":null,"logs":["Program log: hello"],"accounts":null,"unitsConsumed":1000}}`
2694+
server, closer := mockJSONRPC(t, stdjson.RawMessage(wrapIntoRPC(responseBody)))
2695+
defer closer()
2696+
client := New(server.URL)
2697+
2698+
txData := []byte{1, 2, 3, 4}
2699+
minContextSlot := uint64(100)
2700+
out, err := client.SimulateRawTransactionWithOpts(
2701+
context.Background(),
2702+
txData,
2703+
&SimulateTransactionOpts{
2704+
SigVerify: true,
2705+
Commitment: CommitmentProcessed,
2706+
ReplaceRecentBlockhash: true,
2707+
InnerInstructions: true,
2708+
MinContextSlot: &minContextSlot,
2709+
Accounts: &SimulateTransactionAccountsOpts{
2710+
Encoding: solana.EncodingBase64,
2711+
Addresses: []solana.PublicKey{solana.MustPublicKeyFromBase58("7xLk17EQQ5KLDLDe44wCmupJKJjTGd8hs3eSVVhCx932")},
2712+
},
2713+
},
2714+
)
2715+
require.NoError(t, err)
2716+
assert.NotNil(t, out)
2717+
2718+
reqBody := server.RequestBody(t)
2719+
reqBody["id"] = any(nil)
2720+
2721+
assert.Equal(t,
2722+
map[string]any{
2723+
"id": any(nil),
2724+
"jsonrpc": "2.0",
2725+
"method": "simulateTransaction",
2726+
"params": []any{
2727+
base64.StdEncoding.EncodeToString(txData),
2728+
map[string]any{
2729+
"encoding": "base64",
2730+
"sigVerify": true,
2731+
"commitment": string(CommitmentProcessed),
2732+
"replaceRecentBlockhash": true,
2733+
"innerInstructions": true,
2734+
"minContextSlot": float64(100),
2735+
"accounts": map[string]any{
2736+
"encoding": string(solana.EncodingBase64),
2737+
"addresses": []any{"7xLk17EQQ5KLDLDe44wCmupJKJjTGd8hs3eSVVhCx932"},
2738+
},
2739+
},
2740+
},
2741+
},
2742+
reqBody,
2743+
)
2744+
}
2745+
2746+
func TestClient_SimulateTransaction_InnerInstructions(t *testing.T) {
2747+
responseBody := `{"context":{"slot":300},"value":{"logs":["Program log: invoke"],"accounts":null,"unitsConsumed":5000,"innerInstructions":[{"index":0,"instructions":[{"programIdIndex":2,"accounts":[0,1],"data":"3Bxs4ThwQbE4vyj5","stackHeight":2}]}],"returnData":{"programId":"83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri","data":["KgAAAAAAAAA=","base64"]}}}`
2748+
server, closer := mockJSONRPC(t, stdjson.RawMessage(wrapIntoRPC(responseBody)))
2749+
defer closer()
2750+
client := New(server.URL)
2751+
2752+
txData := []byte{1, 2, 3, 4}
2753+
out, err := client.SimulateRawTransactionWithOpts(
2754+
context.Background(),
2755+
txData,
2756+
&SimulateTransactionOpts{
2757+
InnerInstructions: true,
2758+
},
2759+
)
2760+
require.NoError(t, err)
2761+
2762+
require.Len(t, out.Value.InnerInstructions, 1)
2763+
assert.Equal(t, uint16(0), out.Value.InnerInstructions[0].Index)
2764+
require.Len(t, out.Value.InnerInstructions[0].Instructions, 1)
2765+
assert.Equal(t, uint16(2), out.Value.InnerInstructions[0].Instructions[0].ProgramIDIndex)
2766+
assert.Equal(t, []uint16{0, 1}, out.Value.InnerInstructions[0].Instructions[0].Accounts)
2767+
assert.Equal(t, uint16(2), out.Value.InnerInstructions[0].Instructions[0].StackHeight)
2768+
2769+
require.NotNil(t, out.Value.ReturnData)
2770+
assert.Equal(t, solana.MustPublicKeyFromBase58("83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri"), out.Value.ReturnData.ProgramId)
2771+
2772+
expected := mustJSONToInterface([]byte(responseBody))
2773+
got := mustJSONToInterface(mustAnyToJSON(out))
2774+
assert.Equal(t, expected, got, "both deserialized values must be equal")
2775+
}
2776+
2777+
func TestClient_SimulateTransaction_FullResult(t *testing.T) {
2778+
responseBody := `{"context":{"slot":400},"value":{"logs":["Program log: ok"],"accounts":null,"unitsConsumed":3000,"loadedAccountsDataSize":1024,"fee":5000,"preBalances":[10000000,0],"postBalances":[9995000,0],"loadedAddresses":{"readonly":["11111111111111111111111111111111"],"writable":[]},"replacementBlockhash":{"blockhash":"EETubP5AKHgjPAhzPkToc6S4eibc4FFqQGnHR1Sh9rAr","lastValidBlockHeight":500}}}`
2779+
server, closer := mockJSONRPC(t, stdjson.RawMessage(wrapIntoRPC(responseBody)))
2780+
defer closer()
2781+
client := New(server.URL)
2782+
2783+
txData := []byte{1, 2, 3, 4}
2784+
out, err := client.SimulateRawTransactionWithOpts(
2785+
context.Background(),
2786+
txData,
2787+
&SimulateTransactionOpts{
2788+
ReplaceRecentBlockhash: true,
2789+
InnerInstructions: true,
2790+
},
2791+
)
2792+
require.NoError(t, err)
2793+
2794+
assert.Nil(t, out.Value.Err)
2795+
assert.Equal(t, uint64(3000), *out.Value.UnitsConsumed)
2796+
assert.Equal(t, uint32(1024), *out.Value.LoadedAccountsDataSize)
2797+
assert.Equal(t, uint64(5000), *out.Value.Fee)
2798+
assert.Equal(t, []uint64{10000000, 0}, out.Value.PreBalances)
2799+
assert.Equal(t, []uint64{9995000, 0}, out.Value.PostBalances)
2800+
require.NotNil(t, out.Value.ReplacementBlockhash)
2801+
assert.Equal(t, uint64(500), out.Value.ReplacementBlockhash.LastValidBlockHeight)
2802+
require.NotNil(t, out.Value.LoadedAddresses)
2803+
assert.Len(t, out.Value.LoadedAddresses.ReadOnly, 1)
2804+
2805+
expected := mustJSONToInterface([]byte(responseBody))
2806+
got := mustJSONToInterface(mustAnyToJSON(out))
2807+
assert.Equal(t, expected, got, "both deserialized values must be equal")
26522808
}
26532809

26542810
func TestClient_GetFeeForMessage(t *testing.T) {

rpc/simulateTransaction.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,41 @@ type SimulateTransactionResult struct {
4343

4444
// The number of compute budget units consumed during the processing of this transaction.
4545
UnitsConsumed *uint64 `json:"unitsConsumed,omitempty"`
46+
47+
// The size of loaded accounts data in bytes.
48+
LoadedAccountsDataSize *uint32 `json:"loadedAccountsDataSize,omitempty"`
49+
50+
// The most-recent return data generated by an instruction in the transaction.
51+
ReturnData *ReturnData `json:"returnData,omitempty"`
52+
53+
// If innerInstructions were requested, a list of inner instructions.
54+
InnerInstructions []InnerInstruction `json:"innerInstructions,omitempty"`
55+
56+
// The replacement blockhash used when replaceRecentBlockhash is true.
57+
ReplacementBlockhash *ReplacementBlockhash `json:"replacementBlockhash,omitempty"`
58+
59+
// Fee this transaction was charged.
60+
Fee *uint64 `json:"fee,omitempty"`
61+
62+
// Array of u64 account balances from before the transaction was processed.
63+
PreBalances []uint64 `json:"preBalances,omitempty"`
64+
65+
// Array of u64 account balances after the transaction was processed.
66+
PostBalances []uint64 `json:"postBalances,omitempty"`
67+
68+
// List of token balances from before the transaction was processed.
69+
PreTokenBalances []TokenBalance `json:"preTokenBalances,omitempty"`
70+
71+
// List of token balances from after the transaction was processed.
72+
PostTokenBalances []TokenBalance `json:"postTokenBalances,omitempty"`
73+
74+
// Addresses loaded from address lookup tables.
75+
LoadedAddresses *LoadedAddresses `json:"loadedAddresses,omitempty"`
76+
}
77+
78+
type ReplacementBlockhash struct {
79+
Blockhash solana.Hash `json:"blockhash"`
80+
LastValidBlockHeight uint64 `json:"lastValidBlockHeight"`
4681
}
4782

4883
// SimulateTransaction simulates sending a transaction.
@@ -70,6 +105,14 @@ type SimulateTransactionOpts struct {
70105
// (default: false, conflicts with SigVerify)
71106
ReplaceRecentBlockhash bool
72107

108+
// If true the response will include inner instructions.
109+
// These inner instructions will be jsonParsed where possible,
110+
// otherwise json. (default: false)
111+
InnerInstructions bool
112+
113+
// The minimum slot that the request can be evaluated at.
114+
MinContextSlot *uint64
115+
73116
Accounts *SimulateTransactionAccountsOpts
74117
}
75118

@@ -118,6 +161,12 @@ func (cl *Client) SimulateRawTransactionWithOpts(
118161
if opts.ReplaceRecentBlockhash {
119162
obj["replaceRecentBlockhash"] = opts.ReplaceRecentBlockhash
120163
}
164+
if opts.InnerInstructions {
165+
obj["innerInstructions"] = opts.InnerInstructions
166+
}
167+
if opts.MinContextSlot != nil {
168+
obj["minContextSlot"] = *opts.MinContextSlot
169+
}
121170
if opts.Accounts != nil {
122171
obj["accounts"] = M{
123172
"encoding": opts.Accounts.Encoding,

0 commit comments

Comments
 (0)