Skip to content

Commit

Permalink
Merge pull request #149 from avianlabs/guillermo/add-simulate-transac…
Browse files Browse the repository at this point in the history
…tion

add simulate transaction rpc
  • Loading branch information
wiyarmir authored Oct 30, 2024
2 parents f4e86de + 1ae0934 commit b292c2b
Show file tree
Hide file tree
Showing 2 changed files with 137 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
package net.avianlabs.solana.methods

import io.ktor.util.*
import kotlinx.serialization.Contextual
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.*
import net.avianlabs.solana.SolanaClient
import net.avianlabs.solana.client.Response
import net.avianlabs.solana.client.Response.RPC
import net.avianlabs.solana.domain.core.Commitment
import net.avianlabs.solana.domain.core.Transaction

/**
* Simulate a transaction and return the result
*
* @param transaction Transaction to simulate
* @param commitment Commitment level to simulate the transaction at
* @param sigVerify if true the transaction signatures will be verified (conflicts with
* replaceRecentBlockhash)
* @param replaceRecentBlockhash if true the transaction recent blockhash will be replaced with the
* most recent blockhash. (conflicts with sigVerify)
* @param minContextSlot the minimum slot that the request can be evaluated at
* @param innerInstructions If true the response will include inner instructions. These inner
* instructions will be jsonParsed where possible, otherwise json.
* @param accounts Accounts configuration object
*
* @return Simulated transaction result
*/
public suspend fun SolanaClient.simulateTransaction(
transaction: Transaction,
commitment: Commitment? = null,
sigVerify: Boolean? = null,
replaceRecentBlockhash: Boolean? = null,
minContextSlot: ULong? = null,
innerInstructions: Boolean? = null,
accounts: List<String>? = null,
): Response<RPC<SimulateTransactionResponse>> = invoke(
method = "simulateTransaction",
params = buildJsonArray {
add(transaction.serialize().encodeBase64())
addJsonObject {
put("encoding", "base64")
commitment?.let { put("commitment", it.value) }
sigVerify?.let { put("sigVerify", it) }
replaceRecentBlockhash?.let { put("replaceRecentBlockhash", it) }
minContextSlot?.let { put("minContextSlot", it.toString()) }
innerInstructions?.let { put("innerInstructions", it) }
accounts?.let {
putJsonObject("accounts") {
putJsonArray("addresses") {
it.forEach { add(it) }
}
put("encoding", "base58")
}
}
}
}
)

@Serializable
public data class SimulateTransactionResponse(
/**
* Error if transaction failed, null if transaction succeeded.
*/
@Contextual val err: Any?,
/**
* Array of log messages the transaction instructions output during execution, null if simulation
* failed before the transaction was able to execute (for example due to an invalid blockhash or
* signature verification failure)
*/
val logs: List<String>?,
/**
* Accounts requested if any
*/
val accounts: List<AccountInfo>?,
/**
* The number of compute budget units consumed during the processing of this transaction
*/
val unitsConsumed: ULong,
/**
* the most-recent return data generated by an instruction in the transaction
*/
val returnData: ReturnData?,
/**
* Defined only if innerInstructions was set to true
*/
@Contextual val innerInstructions: Any?,
) {
@Serializable
public data class AccountInfo(
/**
* Number of lamports assigned to this account
*/
val lamports: ULong,
/**
* Base-58 encoded Pubkey of the program this account has been assigned to
*/
val owner: String,
/**
* Data associated with the account, either as encoded binary data or JSON format
*/
@Contextual val data: Any,
/**
* Boolean indicating if the account contains a program (and is strictly read-only)
*/
val executable: Boolean,
/**
* The epoch at which this account will next owe rent
*/
val rentEpoch: ULong,
)

@Serializable
public data class ReturnData(
/**
* The program that generated the return data
*/
val programId: String,
/**
* The return data itself, as base-64 encoded binary data
*/
@Contextual val data: Any,
)
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package net.avianlabs.solana.domain.program

import io.ktor.client.*
import io.ktor.client.plugins.logging.*
import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking
import net.avianlabs.solana.SolanaClient
Expand All @@ -20,7 +22,13 @@ class SystemProgramTest {
@Test
@Ignore
fun testCreateDurableNonceAccount() = runBlocking {
val client = SolanaClient(client = RpcKtorClient("http://localhost:8899"))
val client =
SolanaClient(client = RpcKtorClient("http://localhost:8899", httpClient = HttpClient {
install(Logging) {
level = LogLevel.ALL
logger = Logger.SIMPLE
}
}))

val keypair = TweetNaCl.Signature.generateKey(Random.nextBytes(32))
println("Keypair: ${keypair.publicKey}")
Expand Down Expand Up @@ -56,6 +64,10 @@ class SystemProgramTest {
.sign(listOf(keypair, nonceAccount))


val simulated = client.simulateTransaction(initTransaction)

println("simulated: $simulated")

val initSignature = client.sendTransaction(initTransaction)

println("Initialized nonce account: $initSignature")
Expand Down

0 comments on commit b292c2b

Please sign in to comment.