@@ -2648,7 +2648,163 @@ func TestClient_IsBlockhashValid(t *testing.T) {
26482648}
26492649
26502650func 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
26542810func TestClient_GetFeeForMessage(t *testing.T) {
0 commit comments