Skip to main content

getLedgerEntries

For reading the current value of ledger entries directly.

Allows you to directly inspect the current state of a contract, a contract's code, or any other ledger entry. This is a backup way to access your contract data which may not be available via events or simulateTransaction.

To fetch contract wasm byte-code, use the ContractCode ledger entry key.

Parameters

  • keys: <xdr.LedgerKey[]> - Array containing the keys of the ledger entries you wish to retrieve. (an array of serialized base64 strings)

Return

  • <object>
    • entries: Array containing the specified ledger entries which were found
      • key: <xdr.LedgerKey> - The key of the ledger entry (serialized in a base64 string)
      • xdr: <xdr.LedgerEntryData> - The current value of the given ledger entry (serialized in a base64 string)
      • lastModifiedLedgerSeq: <number> - The ledger number of the last time this entry was updated (optional)
    • latestLedger: <number> - The current latest ledger observed by the node when this response was generated.

Examples

Request

{
"jsonrpc": "2.0",
"id": 8675309,
"method": "getLedgerEntry",
"params": {
"keys": ["AAAAB+qfy4GuVKKfazvyk4R9P9fpo2n9HICsr+xqvVcTF+DC","AAAABuGr69HGMhJNHrYmkrVICfPPVxkqlKmRGXAskfpmvOyyAAAAFA=="]
}
}

Response

{
"jsonrpc": "2.0",
"id": 8675309,
"result": {
"entries":[
{
"key": "AAAAB+qfy4GuVKKfazvyk4R9P9fpo2n9HICsr+xqvVcTF+DC",
"xdr": "AAAABwAAAADqn8uBrlSin2s78pOEfT/X6aNp/RyArK/sar1XExfgwgAAAAphIGNvbnRyYWN0AAA=",
"lastModifiedLedgerSeq": "13"
}
],
"latestLedger": "179436"
}
}

Generating key Parameters

The example above is querying a deployment of the increment example contract to find out what value is stored in the COUNTER ledger entry. This value can be derived using the following code snippets. You should be able to extrapolate from the provided examples how to get key parameters for other types and values.

Python

note

If you are using the Python stellar_sdk to generate these keys, you will need to install the latest version of the soroban branch of the SDK. This can be done like so:

pip install git+https://github.com/StellarCN/[email protected]
import stellar_sdk.xdr as xdr, stellar_sdk.soroban_types as soroban_types

def get_ledger_key_symbol(contract_id, symbol_text):
ledger_key = xdr.ledger_key.LedgerKey(
type=xdr.ledger_entry_type.LedgerEntryType.CONTRACT_DATA,
contract_data=xdr.ledger_key_contract_data.LedgerKeyContractData(
contract_id=xdr.hash.Hash(bytes.fromhex(contract_id)),
key=soroban_types.Symbol(symbol_text)._to_xdr_sc_val()
)
)
return ledger_key.to_xdr()

print(get_ledger_key_symbol(
"1bface23a759c5517463198ed14a4969cb4a774ca7d24f54b2d7c50a80bcaa89",
"COUNTER"
))

JavaScript

const SorobanClient = require('soroban-client')
const xdr = SorobanClient.xdr

const getLedgerKeySymbol = (contractId, symbolText) => {
const ledgerKey = xdr.LedgerKey.contractData(
new xdr.LedgerKeyContractData({
contractId: Buffer.from(contractId, 'hex'),
key: xdr.ScVal.scvSymbol(symbolText)
})
)
return ledgerKey.toXDR('base64')
}
console.log(getLedgerKeySymbol(
'1bface23a759c5517463198ed14a4969cb4a774ca7d24f54b2d7c50a80bcaa89',
'COUNTER'
))

Requesting an Account

note

This functionality is included in the js soroban-client package as Server.getAccount(address).

Accounts are stored as ledger entries, so we can use this method to look up an account along with it's current sequence number.

const SorobanClient = require('soroban-client')
const xdr = SorobanClient.xdr

const getLedgerKeyAccount = (address) => {
// We can use the `StrKey` library here to decode the address into the public
// key.
const publicKey = SorobanClient.StrKey.decodeEd25519PublicKey(address);

const ledgerKey = xdr.LedgerKey.account(
new xdr.LedgerKeyAccount({
accountId: xdr.PublicKey.publicKeyTypeEd25519(
publicKey
),
})
)
return ledgerKey.toXDR('base64')
}

console.log(getLedgerKeyAccount(
'GCU5YE6IVBOEZ5LUU5N2NB55VPB5YZNFERT65SSTVXTNMS7IEQWXKBM2'
))

# OUTPUT: AAAAAAAAAACp3BPIqFxM9XSnW6aHvavD3GWlJGfuylOt5tZL6CQtdQ==

We then take our output from this function, and use it as the key parameter in our call to the getLedgerEntry method.

{
"jsonrpc": "2.0",
"id": 8675309,
"method": "getLedgerEntries",
"params": {
"keys": ["AAAAAAAAAACp3BPIqFxM9XSnW6aHvavD3GWlJGfuylOt5tZL6CQtdQ=="]
}
}

And the response we get contains the LedgerEntryData with the current information about this account.

{
"jsonrpc": "2.0",
"id": 8675309,
"result": {
"entries":[
{
"key": "AAAAAAAAAACp3BPIqFxM9XSnW6aHvavD3GWlJGfuylOt5tZL6CQtdQ==",
"xdr": "AAAAAAAAAACp3BPIqFxM9XSnW6aHvavD3GWlJGfuylOt5tZL6CQtdQAAABdIdugAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAA",
"lastModifiedLedgerSeq": "164303"
}
],
"latestLedger": "246819"
}
}

We can then parse this result as an xdr.LedgerEntryData type.

const parsed = xdr.LedgerEntryData.fromXDR(
'AAAAAAAAAACp3BPIqFxM9XSnW6aHvavD3GWlJGfuylOt5tZL6CQtdQAAABdIdugAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAA',
'base64'
)
console.log(parsed);

Requesting a Contract's WASM Code

This can be a bit tricky to wrap your head around, but the conventions do make sense once you let it sink in.

In the previous examples, the COUNTER key was used as a LedgerKey while the incremented value was stored in a LedgerEntry. "Ledger Entry" is the relevant term to keep in mind during this discussion. That LedgerEntry was stored on the Stellar ledger, and was associated with a corresponding LedgerKey. LedgerKey: LedgerEntry works the same way you would think of almost any key: value storage system.

How Soroban Contract Deployment Works

When you deploy a contract, first the code is "installed" (i.e. it is uploaded onto the blockchain). This creates a LedgerEntry containing the WASM byte-code, which is uniquely identified by its hash (that is, the hash of the uploaded code itself). Then, when the contract is "deployed," we create a LedgerEntry with a reference to that code's hash. So fetching the contract code is a two-step process:

  1. First, we look up the contract itself, to see which code hash it is referencing.
  2. Then, we can look up the raw WASM byte-code using that hash.

Request the LedgerKey for the Contract Code

def get_ledger_key_contract_code(contract_id):
ledger_key = xdr.ledger_key.LedgerKey(
type=xdr.ledger_entry_type.LedgerEntryType.CONTRACT_DATA,
contract_data=xdr.ledger_key_contract_data.LedgerKeyContractData(
contract_id=xdr.hash.Hash(bytes.fromhex(contract_id)),
key=xdr.sc_val.SCVal(
type=xdr.sc_val_type.SCValType.SCV_STATIC,
ic=xdr.sc_static.SCStatic.SCS_LEDGER_KEY_CONTRACT_CODE
)
)
)
return ledger_key.to_xdr()
print(get_ledger_key_contract_code(
"1bface23a759c5517463198ed14a4969cb4a774ca7d24f54b2d7c50a80bcaa89"
))
# OUTPUT: AAAABhv6ziOnWcVRdGMZjtFKSWnLSndMp9JPVLLXxQqAvKqJAAAAAwAAAAM=

We then take our output from this function, and use it as the key parameter in our call to the getLedgerEntry method.

{
"jsonrpc": "2.0",
"id": 8675309,
"method": "getLedgerEntry",
"params": {
"keys": ["AAAABhv6ziOnWcVRdGMZjtFKSWnLSndMp9JPVLLXxQqAvKqJAAAAAwAAAAM="],
}
}

And the response we get contains the LedgerEntryData that can be used to find the hash we must use to request the WASM byte-code. This hash is the LedgerKey that's been associated with the deployed contract code.

{
"jsonrpc": "2.0",
"id": 8675309,
"result": {
"entries":[
{
"key": "AAAABhv6ziOnWcVRdGMZjtFKSWnLSndMp9JPVLLXxQqAvKqJAAAAAwAAAAM=",
"xdr": "AAAABhv6ziOnWcVRdGMZjtFKSWnLSndMp9JPVLLXxQqAvKqJAAAAAwAAAAMAAAAEAAAAAQAAAAcAAAAA1CpZRz0BSN27PmqtsmBhv+AAJJwHgmrvJNPrHRAl9l8=",
"lastModifiedLedgerSeq": "164303"
}
],
"latestLedger": "246819"
}
}

Request the ContractCode Using the Retrieved LedgerKey

Now take the xdr field from the previous response's result object, and create a LedgerKey from the hash contained inside.

def get_ledger_key_wasm_id(contract_code_ledger_entry_data):
# First, we dig the wasm_id hash out of the xdr we received from RPC
contract_code_wasm_hash = xdr.ledger_entry_data.LedgerEntryData.from_xdr(
contract_code_ledger_entry_data
).contract_data.val.obj.contract_code.wasm_id.hash
# Now, we can create the `LedgerKey` as we've done in previous examples
ledger_key = xdr.ledger_key.LedgerKey(
type=xdr.ledger_entry_type.LedgerEntryType.CONTRACT_CODE,
contract_code=xdr.ledger_key_contract_code.LedgerKeyContractCode(
hash=xdr.hash.Hash(contract_code_wasm_hash)
)
)
return ledger_key.to_xdr()
print(get_ledger_key_wasm_id(
"AAAABhv6ziOnWcVRdGMZjtFKSWnLSndMp9JPVLLXxQqAvKqJAAAAAwAAAAMAAAAEAAAAAQAAAAcAAAAA1CpZRz0BSN27PmqtsmBhv+AAJJwHgmrvJNPrHRAl9l8="
))
# OUTPUT: AAAAB9QqWUc9AUjduz5qrbJgYb/gACScB4Jq7yTT6x0QJfZf

Now, finally we have a LedgerKey that correspond to the WASM byte-code that has been deployed under the ContractId we started out with so very long ago. This LedgerKey can be used in a final request to the Soroban-RPC endpoint.

{
"jsonrpc": "2.0",
"id": 8675309,
"method": "getLedgerEntry",
"params": {
"keys": ["AAAAB9QqWUc9AUjduz5qrbJgYb/gACScB4Jq7yTT6x0QJfZf"]
}
}

And the response we get contains (even more) LedgerEntryData that we can decode and parse to get the actual, deployed, real-life contract byte-code. We'll leave that exercise up to you. You can check out what is contained using the "View XDR" page of the Stellar Laboratory.

{
"jsonrpc": "2.0",
"id": 8675309,
"result": {
"entries":[
{
"key": "AAAAB9QqWUc9AUjduz5qrbJgYb/gACScB4Jq7yTT6x0QJfZf",
"xdr": "AAAABwAAAADUKllHPQFI3bs+aq2yYGG/4AAknAeCau8k0+sdECX2XwAAAakAYXNtAQAAAAEXBWABfgF+YAJ+fgF+YAABfmABfwBgAAACEwMBbAEwAAABbAExAAABbAFfAAEDBgUCAwQEBAUDAQAQBhkDfwFBgIDAAAt/AEGAgMAAC38AQYCAwAALBzUFBm1lbW9yeQIACWluY3JlbWVudAADAV8ABwpfX2RhdGFfZW5kAwELX19oZWFwX2Jhc2UDAgrAAQWhAQMBfwF+AX8jgICAgABBEGsiACSAgICAAAJAAkBC2YP9sqDNAxCAgICAAEIVUg0AAkBC2YP9sqDNAxCBgICAACIBQg+DQgFSDQAgAUIEiKchAgwCCyAAQQhqEISAgIAAAAtBACECCwJAIAJBAWoiAg0AEIWAgIAAAAtC2YP9sqDNAyACrUIEhkIBhCIBEIKAgIAAGiAAQRBqJICAgIAAIAELCQAQhoCAgAAACwkAEIaAgIAAAAsEAAAACwIACwAeEWNvbnRyYWN0ZW52bWV0YXYwAAAAAAAAAAAAAAAbAC8OY29udHJhY3RzcGVjdjAAAAAAAAAACWluY3JlbWVudAAAAAAAAAAAAAABAAAAAQAAAA==",
"lastModifiedLedgerSeq": "164302"
}
],
"latestLedger": "246883"
}
}