getLedgerEntries
For reading the current value of ledger entries directly.
This method enables querying live ledger state: accounts, trustlines, offers, data, claimable balances, and liquidity pools. It also provides direct access to inspect a contract's current state, its code, or any other ledger entry. This serves as a primary method 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.
Params
(2)Please note that parameter structure within the request must contain named parameters as a by-name object, and not as positional arguments in a by-position array
1. keys (required)
Array containing the keys of the ledger entries you wish to retrieve. (an array of serialized base64 strings)
An array of LedgerKeys. The maximum number of ledger keys accepted is 200.
2. xdrFormat
Lets the user choose the format in which the response should be returned - either as unpacked JSON or as base64-encoded XDR strings. Note that you should not rely on any schema for the JSON, as it will change when the underlying XDR changes.
Specifies whether XDR should be encoded as Base64 (default or 'base64') or JSON ('json').
Result
(getLedgerEntriesResult)The sequence number of the latest ledger known to Stellar RPC at the time it handled the request.
Array of objects containing all found ledger entries
The LedgerKey corresponding to the ledger entry (base64 string).
The key's current LedgerEntryData value (base64 string).
The ledger sequence number of the last time this entry was updated.
Sequence number of the ledger.
Examples
Example request to the getNetwork
method for a Counter(Address)
ledger entry.
Request
- cURL
- JavaScript
- Python
- JSON
curl -X POST \
-H 'Content-Type: application/json' \
-d '{
"jsonrpc": "2.0",
"id": 8675309,
"method": "getLedgerEntries",
"params": {
"keys": [
"AAAABgAAAAHMA/50/Q+w3Ni8UXWm/trxFBfAfl6De5kFttaMT0/ACwAAABAAAAABAAAAAgAAAA8AAAAHQ291bnRlcgAAAAASAAAAAAAAAAAg4dbAxsGAGICfBG3iT2cKGYQ6hK4sJWzZ6or1C5v6GAAAAAE="
]
}
}' \
https://soroban-testnet.stellar.org | jq
let requestBody = {
"jsonrpc": "2.0",
"id": 8675309,
"method": "getLedgerEntries",
"params": {
"keys": [
"AAAABgAAAAHMA/50/Q+w3Ni8UXWm/trxFBfAfl6De5kFttaMT0/ACwAAABAAAAABAAAAAgAAAA8AAAAHQ291bnRlcgAAAAASAAAAAAAAAAAg4dbAxsGAGICfBG3iT2cKGYQ6hK4sJWzZ6or1C5v6GAAAAAE="
]
}
}
let res = await fetch('https://soroban-testnet.stellar.org', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(requestBody),
})
let json = await res.json()
console.log(json)
import json, requests
res = requests.post(https://soroban-testnet.stellar.org, json={
"jsonrpc": "2.0",
"id": 8675309,
"method": "getLedgerEntries",
"params": {
"keys": [
"AAAABgAAAAHMA/50/Q+w3Ni8UXWm/trxFBfAfl6De5kFttaMT0/ACwAAABAAAAABAAAAAgAAAA8AAAAHQ291bnRlcgAAAAASAAAAAAAAAAAg4dbAxsGAGICfBG3iT2cKGYQ6hK4sJWzZ6or1C5v6GAAAAAE="
]
}
})
print(json.dumps(res.json(), indent=4))
{
"jsonrpc": "2.0",
"id": 8675309,
"method": "getLedgerEntries",
"params": {
"keys": [
"AAAABgAAAAHMA/50/Q+w3Ni8UXWm/trxFBfAfl6De5kFttaMT0/ACwAAABAAAAABAAAAAgAAAA8AAAAHQ291bnRlcgAAAAASAAAAAAAAAAAg4dbAxsGAGICfBG3iT2cKGYQ6hK4sJWzZ6or1C5v6GAAAAAE="
]
}
}
Result
{
"jsonrpc": "2.0",
"id": 8675309,
"result": {
"entries": [
{
"key": "AAAAB+qfy4GuVKKfazvyk4R9P9fpo2n9HICsr+xqvVcTF+DC",
"xdr": "AAAABgAAAAAAAAABzAP+dP0PsNzYvFF1pv7a8RQXwH5eg3uZBbbWjE9PwAsAAAAQAAAAAQAAAAIAAAAPAAAAB0NvdW50ZXIAAAAAEgAAAAAAAAAAIOHWwMbBgBiAnwRt4k9nChmEOoSuLCVs2eqK9Qub+hgAAAABAAAAAwAAAAw=",
"lastModifiedLedgerSeq": 2552504
}
],
"latestLedger": 2552990
}
}
Creando claves del ledger
El ledger de Stellar es, en cierto modo, esencialmente un almacén de pares clave-valor. Las claves son instancias de LedgerKey
y los valores son instancias de LedgerEntry
. Un producto interesante del diseño interno del almacén es que la clave es un subconjunto de la entrada: más adelante veremos más sobre esto.
El método getLedgerEntries
devuelve los "valores" (o "entradas") para un conjunto dado de "claves". Las claves del ledger vienen en muchas formas, y repasaremos las más comúnmente utilizadas en esta página junto con tutoriales sobre cómo crear y usarlas.
Tipos de LedgerKey
La fuente de verdad siempre debe ser el XDR definido en el protocolo. LedgerKey
son un tipo de unión definido en Stellar-ledger-entries.x. Hay 10 formas diferentes que puede tomar una clave de ledger:
- Cuenta: define holísticamente una cuenta de Stellar, incluyendo su saldo, firmantes, etc. (ver Cuentas)
- Línea de confianza: define una línea de saldo para un activo no nativo emitido en la red (ver
changeTrustOp
) - Oferta: define una oferta hecha en el DEX de Stellar (ver Liquidez en Stellar)
- Datos de Cuenta: define entradas de datos clave-valor adjuntas a una cuenta (ver
manageDataOp
) - Saldo reclamable: define un saldo que puede o no ser reclamable activamente (ver Saldos Reclamables)
- Fondo de Liquidez: define la configuración de un fondo de liquidez constante nativo entre dos activos (ver Liquidez en Stellar)
- Datos de Contrato: define un conjunto de datos que se almacena en un contrato bajo una clave
- Código de Contrato: define el bytecode Wasm de un contrato
- Ajuste de Configuración: define la configuración de red actualmente activa
- TTL: define el tiempo de vida de una entrada de datos de contrato o código asociada
Nos enfocaremos en un subconjunto de estos para obtener el máximo valor, pero una vez que entiendas cómo crear y analizar algunas claves y entradas, puedes extrapolar a todas ellas.
Cuentas
Para obtener una cuenta, todo lo que necesitas es su clave pública:
import { Keypair, xdr } from "@stellar/stellar-sdk";
const publicKey = "GALAXYVOIDAOPZTDLHILAJQKCVVFMD4IKLXLSZV5YHO7VY74IWZILUTO";
const accountLedgerKey = xdr.LedgerKey.ledgerKeyAccount(
new xdr.LedgerKeyAccount({
accountId: Keypair.fromPublicKey(publicKey).xdrAccountId(),
}),
);
console.log(accountLedgerKey.toXDR("base64"));
Esto te dará los detalles completos de la cuenta.
const accountEntryData = (
await s.getLedgerEntries(accountLedgerKey)
).entries[0].account();
Si solo quieres echar un vistazo a la estructura, puedes pasar el valor base64 crudo que hemos registrado arriba al Laboratorio (o a través de curl
si pasas "xdrFormat": "json"
como un parámetro adicional a getLedgerEntries
) y ver todos los campos posibles. También puedes explorarlos en código, por supuesto:
console.log(
`Account ${publicKey} has ${accountEntryData
.balance()
.toString()} stroops of XLM and is on sequence number ${accountEntryData
.seqNum()
.toString()}`,
);
Líneas de confianza
Una línea de confianza es una entrada de saldo para cualquier activo no nativo (como USDC de Circle). Para obtener una, necesitas el propietario de la línea de confianza (una clave pública como para Cuentas) y el activo en cuestión:
const trustlineLedgerKey = xdr.LedgerKey.ledgerKeyTrustLine(
new xdr.LedgerKeyTrustLine({
accountId: Keypair.fromPublicKey(publicKey).xdrAccountId(),
asset: new Asset(
"USDC",
"GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN",
).toTrustLineXDRObject(),
}),
);
Al igual que en una cuenta, la entrada resultante tiene un saldo, pero también tiene un límite y banderas para controlar cuánto de ese activo se puede mantener. El activo, sin embargo, puede ser un activo emitido o un fondo de liquidez:
let asset: string;
let rawAsset = trustlineEntryData.asset();
switch (rawAsset.switch().value) {
case AssetType.assetTypeCreditAlphanum4().value:
asset = Asset.fromOperation(
xdr.Asset.assetTypeCreditAlphanum4(rawAsset.alphaNum4()),
).toString();
break;
case AssetType.assetTypeCreditAlphanum12().value:
asset = Asset.fromOperation(
xdr.Asset.assetTypeCreditAlphanum12(rawAsset.alphaNum12()),
).toString();
break;
case AssetType.assetTypePoolShare().value:
asset = rawAsset.liquidityPoolId().toXDR("hex");
break;
}
console.log(
`Account ${publicKey} has ${trustlineEntryData
.balance()
.toString()} stroops of ${asset} with a limit of ${trustlineEntryData
.balance()
.toString()}`,
);
Datos de Contrato
Supongamos que hemos desplegado el [incrementar
ejemplo de contrato] y queremos averiguar qué valor está almacenado en la clave del ledger COUNTER
. Para crear la clave:
- Python
- TypeScript
from stellar_sdk import xdr, scval, Address
def get_ledger_key_symbol(contract_id: str, symbol_text: str) -> str:
ledger_key = xdr.LedgerKey(
type=xdr.LedgerEntryType.CONTRACT_DATA,
contract_data=xdr.LedgerKeyContractData(
contract=Address(contract_id).to_xdr_sc_address(),
key=scval.to_symbol(symbol_text),
durability=xdr.ContractDataDurability.PERSISTENT
),
)
return ledger_key.to_xdr()
print(
get_ledger_key_symbol(
"CCPYZFKEAXHHS5VVW5J45TOU7S2EODJ7TZNJIA5LKDVL3PESCES6FNCI",
"COUNTER"
)
)
import { xdr, Address } from "@stellar/stellar-sdk";
const getLedgerKeySymbol = (
contractId: string,
symbolText: string,
): xdr.LedgerKey => {
return xdr.LedgerKey.contractData(
new xdr.LedgerKeyContractData({
contract: new Address(contractId).toScAddress(),
key: xdr.ScVal.scvSymbol(symbolText),
// The increment contract stores its state in persistent storage,
// but other contracts may use temporary storage
// (xdr.ContractDataDurability.temporary()).
durability: xdr.ContractDataDurability.persistent(),
}),
);
};
const ledgerKey = getLedgerKeySymbol(
"CCPYZFKEAXHHS5VVW5J45TOU7S2EODJ7TZNJIA5LKDVL3PESCES6FNCI",
"COUNTER",
);
Código de Contrato Wasm
Para entender esto, necesitamos comprender cómo funciona el despliegue de contratos inteligentes:
- Cuando despliegas un contrato, primero el código se "instala" (es decir, se carga en la blockchain), creando una
LedgerEntry
con el bytecode Wasm que puede ser identificado de manera única por su hash (es decir, el hash del código subido). - Luego, cuando una instancia de contrato es "instanciada," creamos una
LedgerEntry
con una referencia al hash de ese código. Esto significa que muchos contratos pueden apuntar al mismo código Wasm.
Por lo tanto, obtener el código del contrato es un proceso de dos pasos:
- Primero, buscamos el contrato mismo, para ver a qué hash de código está haciendo referencia.
- Luego, podemos buscar el bytecode Wasm crudo usando ese hash.
1. Encuentra la clave del ledger para la instancia del contrato
- Python
- TypeScript
from stellar_sdk import xdr, Address
def get_ledger_key_contract_code(contract_id: str) -> xdr.LedgerKey:
return xdr.LedgerKey(
type=xdr.LedgerEntryType.CONTRACT_DATA,
contract_data=xdr.LedgerKeyContractData(
contract=Address(contract_id).to_xdr_sc_address(),
key=xdr.SCVal(xdr.SCValType.SCV_LEDGER_KEY_CONTRACT_INSTANCE),
durability=xdr.ContractDataDurability.PERSISTENT
)
)
print(get_ledger_key_contract_code(
"CCPYZFKEAXHHS5VVW5J45TOU7S2EODJ7TZNJIA5LKDVL3PESCES6FNCI"
))
import { Contract } from "@stellar/stellar-sdk";
function getLedgerKeyContractCode(contractId): xdr.LedgerKey {
return new Contract(contractId).getFootprint();
}
console.log(
getLedgerKeyContractCode(
"CCPYZFKEAXHHS5VVW5J45TOU7S2EODJ7TZNJIA5LKDVL3PESCES6FNCI",
),
);
Una vez que tengamos la entrada del ledger (a través de getLedgerEntries
, ver abajo), podemos extraer el hash Wasm:
2. Solicita el ContractCode
utilizando el LedgerKey
recuperado
Ahora toma el campo xdr
del objeto result
de la respuesta anterior, y crea un LedgerKey
a partir del hash contenido dentro.
- Python
- TypeScript
from stellar_sdk import xdr
def get_ledger_key_wasm_id(
# received from getLedgerEntries and decoded
contract_data: xdr.ContractDataEntry
) -> xdr.LedgerKey:
# First, we dig the wasm_id hash out of the xdr we received from RPC
wasm_hash = contract_data.val.instance.executable.wasm_hash
# Now, we can create the `LedgerKey` as we've done in previous examples
ledger_key = xdr.LedgerKey(
type=xdr.LedgerEntryType.CONTRACT_CODE,
contract_code=xdr.LedgerKeyContractCode(
hash=wasm_hash
),
)
return ledger_key
import { xdr } from "@stellar/stellar-sdk";
function getLedgerKeyWasmId(
contractData: xdr.ContractDataEntry,
): xdr.LedgerKey {
const wasmHash = contractData.val().instance().executable().wasmHash();
return xdr.LedgerKey.contractCode(
new xdr.LedgerKeyContractCode({
hash: wasmHash,
}),
);
}
Ahora, finalmente tenemos un LedgerKey
que corresponde al bytecode Wasm que ha sido desplegado bajo el contractId
con el que comenzamos hace tanto tiempo. Este LedgerKey
puede ser utilizado en una solicitud final a getLedgerEntries
. En esa respuesta obtendremos un LedgerEntryData
correspondiente a un ContractCodeEntry
que contendrá el bytecode del contrato real, desplegado y en la vida real:
const theHashData: xdr.ContractDataEntry = await getLedgerEntries(
getLedgerKeyContractCode("C..."),
).entries[0].contractData();
const theCode: Buffer = await getLedgerEntries(getLedgerKeyWasmId(theHashData))
.entries[0].contractCode()
.code();
Obteniendo realmente los datos de la entrada del ledger
Una vez que hayamos aprendido a crear y analizar estos (lo cual ya hemos hecho antes), el proceso para obtenerlos es siempre idéntico. Si conoces el tipo de clave que obtuviste, aplicas el método de acceso correspondiente una vez que los hayas recibido del método getLedgerEntries
:
const s = new Server("https://soroban-testnet.stellar.org");
// assume key1 is an account, key2 is a trustline, and key3 is contract data
const response = await s.getLedgerEntries(key1, key2, key3);
const account = response.entries[0].account();
const contractData = response.entries[2].contractData();
const contractCode = response.entries[1].contractCode();
Ahora, finalmente tenemos un LedgerKey
que corresponde al bytecode Wasm que ha sido desplegado bajo el ContractId
con el que comenzamos hace tanto tiempo. Este LedgerKey
puede ser utilizado en una solicitud final al punto final Stellar-RPC.
{
"jsonrpc": "2.0",
"id": 12345,
"method": "getLedgerEntries",
"params": {
"keys": [
"AAAAB+QzbW3JDhlUbDVW/C+1/5SIQDstqORuhpCyl73O1vH6",
"AAAABgAAAAGfjJVEBc55drW3U87N1Py0Rw0/nlqUA6tQ6r28khEl4gAAABQAAAAB"
"AAAABgAAAAAAAAABn4yVRAXOeXa1t1POzdT8tEcNP55alAOrUOq9vJIRJeIAAAAUAAAAAQAAABMAAAAA5DNtbckOGVRsNVb8L7X/lIhAOy2o5G6GkLKXvc7W8foAAAAA"
]
}
}
Luego puedes inspeccionarlos según sea necesario. Cada una de las entradas anteriores sigue el XDR para esa estructura de LedgerEntryData
con precisión. Por ejemplo, el AccountEntry
está en Stellar-ledger-entries.x#L191
y puedes usar .seqNum()
para acceder a su número de secuencia actual, como hemos mostrado. En JavaScript, puedes ver los métodos apropiados en la definición de tipo.
Ver y entender XDR
Si no deseas analizar el XDR programáticamente, también puedes aprovechar tanto el CLI de Stellar como el Laboratorio de Stellar para obtener una vista legible por humanos de las claves y entradas del ledger. Por ejemplo,
echo 'AAAAAAAAAAAL76GC5jcgEGfLG9+nptaB9m+R44oweeN3EcqhstdzhQ==' | stellar xdr decode --type LedgerKey --output json-formatted
{
"account": {
"account_id": "GAF67IMC4Y3SAEDHZMN57J5G22A7M34R4OFDA6PDO4I4VINS25ZYLBZZ"
}
}