You can find the getLatestBlockhash
method on the Connection
class that's exported by @solana/web3.js
You can find the reference in the documentation here.
Basic usage
To use it, you need to initialize the Connection class and you can call it, like so:
import { Connection } from '@solana/web3.js'
const conn = new Connection('your-rpc-endpoint', 'confirmed')
const result = await conn.getLatestBlockhash()
console.log(result)
This will output the blockhash
and the lastValidBlockHeight
:
{
blockhash: 'G4oTG19N9mkWfNv6VUJzTtGCTFx2xw4JgWF1MhKA4hdG',
lastValidBlockHeight: 225956979
}
Adding a cache
The @solana/web3.js
package does not come with cache out of the box, but it's pretty easy to add it yourself.
In the example below, I'm using the library lru-cache but you can use other libraries.
To get this working, we first install the package and add it to our imports:
import { Connection } from '@solana/web3.js'
import { LRUCache } from 'lru-cache'
Next up, we define a cache that lives for 30 seconds:
// We need our connection
const conn = new Connection('your-rpc-endpoint', 'confirmed')
const cache = new LRUCache<string, string>({
max: 1000,
// 30 seconds
ttl: 1000 * 30,
// Define the fetch method for this cache
fetchMethod: async () => {
const result = await conn.getLatestBlockhash()
console.log(`[CACHE WRITE] blockhash ${result.blockhash}`)
return result.blockhash
}
})
With this in place, we can call the fetch()
function on the cache
instance. It will retrieve the blockhash from the cache; if not found there, it will obtain it from Solana and store it in the cache.
You can see an example here:
async function main() {
// Show the cached blockhash for 60 seconds
const attempts = 60
for (let i = 0; i < attempts; i++) {
const start = Date.now()
// Get the cached blockhash
const blockhash = await cache.fetch('blockhash')
// If the blockhash is not cached, throw an error
if (!blockhash) {
throw new Error('Expected blockhash')
}
// Show the blockhash
console.log(`[CACHE READ] blockhash ${blockhash} took ${Date.now() - start}ms`)
// Wait 1 second
await new Promise((resolve) => setTimeout(resolve, 1000))
}
}
main()
The output looks something like this:
[CACHE WRITE] blockhash DbFB5dTNgUAfshKQVva7hCiXJbUnUeWq8PHfUoFjJKF9
[CACHE READ] blockhash DbFB5dTNgUAfshKQVva7hCiXJbUnUeWq8PHfUoFjJKF9 took 544ms
[CACHE READ] blockhash DbFB5dTNgUAfshKQVva7hCiXJbUnUeWq8PHfUoFjJKF9 took 0ms
[CACHE READ] blockhash DbFB5dTNgUAfshKQVva7hCiXJbUnUeWq8PHfUoFjJKF9 took 0ms
[CACHE READ] blockhash DbFB5dTNgUAfshKQVva7hCiXJbUnUeWq8PHfUoFjJKF9 took 0ms
[CACHE READ] blockhash DbFB5dTNgUAfshKQVva7hCiXJbUnUeWq8PHfUoFjJKF9 took 3ms
[CACHE READ] blockhash DbFB5dTNgUAfshKQVva7hCiXJbUnUeWq8PHfUoFjJKF9 took 0ms
[CACHE READ] blockhash DbFB5dTNgUAfshKQVva7hCiXJbUnUeWq8PHfUoFjJKF9 took 0ms
[CACHE READ] blockhash DbFB5dTNgUAfshKQVva7hCiXJbUnUeWq8PHfUoFjJKF9 took 1ms
........
From looking at the results, there is a huge benefit in doing this and might lead to an enhanced user experience depending on the app.