From 8aea02aa88ebc6e92cef7c5a4e7d21ddf419383a Mon Sep 17 00:00:00 2001 From: George Date: Fri, 25 Oct 2024 12:30:08 -0700 Subject: [PATCH 01/13] Outline building and parsing all sorts of LedgerKeys/EntryDatas --- .../methods/getLedgerEntries.mdx | 405 ++++++++---------- 1 file changed, 190 insertions(+), 215 deletions(-) diff --git a/docs/data/rpc/api-reference/methods/getLedgerEntries.mdx b/docs/data/rpc/api-reference/methods/getLedgerEntries.mdx index faca691f6..385614900 100644 --- a/docs/data/rpc/api-reference/methods/getLedgerEntries.mdx +++ b/docs/data/rpc/api-reference/methods/getLedgerEntries.mdx @@ -10,21 +10,117 @@ import rpcSpec from "@site/static/stellar-rpc.openrpc.json"; method={rpcSpec.methods.filter((meth) => meth.name === "getLedgerEntries")[0]} /> -### Generating `keys` Parameters +The Stellar ledger is, on some level, essentially a key-value store. The keys are `LedgerKey`s and the values are `LedgerEntryData`s in the XDR. An interesting product of the store's internal design is that the key is a _subset_ of the entry: we'll see more of this later. -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 `keys` parameters for other types and values. +The `getLedgerEntries` method returns the "values" (or "entries") for a given set of "keys". `LedgerKey`s come in a lot of forms, and we'll go over the valuable ones on this page alongside tutorials on how to build and use them. -#### Python +## Types of `LedgerKey`s -:::note +The source of truth should always be the XDR defined in the protocol. `LedgerKey`s are a union type defined in [Stellar-ledger-entries.x](https://github.com/stellar/stellar-xdr/blob/529d5176f24c73eeccfa5eba481d4e89c19b1181/Stellar-ledger-entries.x#L600). There are 10 different forms a ledger key can take: -If you are using the [Python](https://stellar-sdk.readthedocs.io/en/latest/) `stellar_sdk` to generate these keys, you will need to install the latest version of the SDK. This can be done like so: +1. Account: holistically defines a Stellar account, including its balance, signers, etc. +2. Trustline: defines a balance line to a non-native asset issued on the network (see [`changeTrustOp`](TODO)) +3. Offer: defines an offer made on the Stellar DEX (see e.g., [`manageOfferOp`](TODO)) +4. Data: defines key-value data entries attached to an account (see [`manageDataOp`](TODO)) +5. Claimable Balance: defines a balance that may or may not actively be claimable (see [`createClaimableBalanceOp`](TODO)) +6. Liquidity Pool: defines the configuration of a native constant liquidity pool between two assets (see [``]()) +7. Contract Data: defines a piece of data being stored in a contract under a key +8. Contract Code: defines the Wasm bytecode of a contract +9. Config Setting: defines the currently active network configuration +10. Ttl: defines the time-to-live of an associated contract data or code entry -```bash -pip install --upgrade stellar-sdk +We're going to focus on a subset of these for maximum value. + +### Accounts + +To fetch an account, all you need is its public key: + +```typescript +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")); ``` -::: +This will give you the full account details. + +```typescript +const accountEntryData = ( + await s.getLedgerEntries(accountLedgerKey) +).entries[0].account(); +``` + +If you just want to take a look at the structure, you can pass the raw base64 value we logged above to the [Laboratory](https://lab.stellar.org/endpoints/rpc/get-ledger-entries?$=network$id=testnet&label=Testnet&horizonUrl=https:////horizon-testnet.stellar.org&rpcUrl=https:////soroban-testnet.stellar.org&passphrase=Test%20SDF%20Network%20/;%20September%202015;&endpoints$params$xdrFormat=json;;) (or via `curl` if you pass `"xdrFormat": "json"` as an additional parameter to `getLedgerEntries`) and see all of the possible fields. You can also dig into them in code, of course: + +```typescript +console.log( + `Account ${publicKey} has ${accountEntryData + .balance() + .toString()} stroops of XLM and is on sequence number ${accountEntryData + .seqNum() + .toString()}`, +); +``` + +### Trustlines + +A trustline is a balance entry for any non-native asset (such as [Circle's USDC](https://stellar.expert/explorer/public/asset/USDC-GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN)). To fetch one, you need the trustline owner (a public key like for [Accounts](#accounts)) and the asset in question: + +```typescript +const trustlineLedgerKey = xdr.LedgerKey.ledgerKeyTrustLine( + new xdr.LedgerKeyTrustLine({ + accountId: Keypair.fromPublicKey(publicKey).xdrAccountId(), + asset: new Asset( + "USDC", + "GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN", + ).toTrustLineXDRObject(), + }), +); +``` + +Much like an [account](#accounts), the resulting entry has a balance, but it also has a limit and flags to control how much of that asset can be held. The asset, however, can be either an issued asset or a liquidity pool: + +```typescript +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()}`, +); +``` + +### Contract Data + +Suppose we've deployed the [`increment` example contract] and want to find out what value is stored in the `COUNTER` ledger key. To build the key, + + ```python from stellar_sdk import xdr, scval, Address @@ -48,129 +144,47 @@ print( ) ``` -#### JavaScript - -If you are using the [JavaScript](https://stellar.github.io/js-stellar-sdk/) `stellar-sdk` to generate these keys, you will need to install the latest pre-release version of the SDK. This can be done like so: - -```bash -yarn add @stellar/stellar-sdk -``` - ```js import { xdr, Address } from "@stellar/stellar-sdk"; const getLedgerKeySymbol = (contractId, symbolText) => { - const ledgerKey = xdr.LedgerKey.contractData( + return xdr.LedgerKey.contractData( new xdr.LedgerKeyContractData({ contract: new Address(contractId).toScAddress(), key: xdr.ScVal.scvSymbol(symbolText), + // or, possibly, .temporary(), depending on your contract durability: xdr.ContractDataDurability.persistent(), }), ); - return ledgerKey.toXDR("base64"); }; -console.log( - getLedgerKeySymbol( - "CCPYZFKEAXHHS5VVW5J45TOU7S2EODJ7TZNJIA5LKDVL3PESCES6FNCI", - "COUNTER", - ), -); -``` - -### Requesting an Account - -:::note - -This functionality is included in the JavaScript [`stellar-sdk`](https://www.npmjs.com/package/stellar-sdk) package as `rpc.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. - -```js -import { xdr, Keypair } from '@stellar/stellar-sdk' - -const getLedgerKeyAccount = (address) => { - const ledgerKey = xdr.LedgerKey.account( - new xdr.LedgerKeyAccount({ - accountId: Keypair.fromPublicKey(address).xdrPublicKey(), - }) - ) - return ledgerKey.toXDR('base64') -} - -console.log(getLedgerKeyAccount( - 'GCU5YE6IVBOEZ5LUU5N2NB55VPB5YZNFERT65SSTVXTNMS7IEQWXKBM2' -)) - -# OUTPUT: AAAAAAAAAACp3BPIqFxM9XSnW6aHvavD3GWlJGfuylOt5tZL6CQtdQ== -``` - -We then take our output from this function, and use it as the element in the `keys` array parameter in our call to the `getLedgerEntries` method. - -```json -{ - "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. - -```json -{ - "jsonrpc": "2.0", - "id": 8675309, - "result": { - "entries": [ - { - "key": "AAAAAAAAAACp3BPIqFxM9XSnW6aHvavD3GWlJGfuylOt5tZL6CQtdQ==", - "xdr": "AAAAAAAAAACp3BPIqFxM9XSnW6aHvavD3GWlJGfuylOt5tZL6CQtdQAAABdIdugAAAWpygAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAA", - "lastModifiedLedgerSeq": "164303" - } - ], - "latestLedger": 246819 - } -} -``` - -We can then parse this result as an `xdr.LedgerEntryData` type. - -```js -const parsed = xdr.LedgerEntryData.fromXDR( - "AAAAAAAAAACp3BPIqFxM9XSnW6aHvavD3GWlJGfuylOt5tZL6CQtdQAAABdIdugAAAWpygAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAA", - "base64", +const ledgerKey = getLedgerKeySymbol( + "CCPYZFKEAXHHS5VVW5J45TOU7S2EODJ7TZNJIA5LKDVL3PESCES6FNCI", + "COUNTER", ); -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. +### Contract Wasm Code -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. +To understand this, we need a handle on how smart contract deployment works: -#### How Soroban Contract Deployment Works +- When you deploy a contract, first the code is "installed" (i.e. uploaded onto the blockchain), creating a `LedgerEntry` with the Wasm byte-code that can be uniquely identified by its hash (that is, the hash of the uploaded code itself). +- Then, when a contract _instance_ is "deployed," we create a `LedgerEntry` with a reference to that code's hash. This means many contracts can point to the same Wasm code. -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: +Thus, 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 +#### 1. Find the ledger key for the contract instance -##### Python + ```python from stellar_sdk import xdr, Address -def get_ledger_key_contract_code(contract_id: str) -> str: - ledger_key = xdr.LedgerKey( +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(), @@ -178,24 +192,17 @@ def get_ledger_key_contract_code(contract_id: str) -> str: durability=xdr.ContractDataDurability.PERSISTENT ) ) - return ledger_key.to_xdr() -print( - get_ledger_key_contract_code( - "CCPYZFKEAXHHS5VVW5J45TOU7S2EODJ7TZNJIA5LKDVL3PESCES6FNCI" - ) -) -# OUTPUT: AAAABgAAAAGfjJVEBc55drW3U87N1Py0Rw0/nlqUA6tQ6r28khEl4gAAABQAAAAB +print(get_ledger_key_contract_code( + "CCPYZFKEAXHHS5VVW5J45TOU7S2EODJ7TZNJIA5LKDVL3PESCES6FNCI" +)) ``` -##### JavaScript - -```javascript +```typescript import { Contract } from "@stellar/stellar-sdk"; -function getLedgerKeyContractCode(contractId) { - const instance = new Contract(contractId).getFootprint(); - return instance.toXDR("base64"); +function getLedgerKeyContractCode(contractId): xdr.LedgerKey { + return new Contract(contractId).getFootprint(); } console.log( @@ -203,139 +210,107 @@ console.log( "CCPYZFKEAXHHS5VVW5J45TOU7S2EODJ7TZNJIA5LKDVL3PESCES6FNCI", ), ); -// OUTPUT: AAAABgAAAAGfjJVEBc55drW3U87N1Py0Rw0/nlqUA6tQ6r28khEl4gAAABQAAAAB ``` -We then take our output from this function, and use it as the element in the `keys` array parameter in our call to the `getLedgerEntries` method. + -```json -{ - "jsonrpc": "2.0", - "id": 8675309, - "method": "getLedgerEntries", - "params": { - "keys": ["AAAABgAAAAGfjJVEBc55drW3U87N1Py0Rw0/nlqUA6tQ6r28khEl4gAAABQAAAAB"] - } -} -``` - -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. +Once we have the ledger entry (via `getLedgerEntries`, see [below](#actually-fetching-the-ledger-entry-data)), we can extract the Wasm hash: -```json -{ - "jsonrpc": "2.0", - "id": 8675309, - "result": { - "entries": [ - { - "key": "AAAABgAAAAGfjJVEBc55drW3U87N1Py0Rw0/nlqUA6tQ6r28khEl4gAAABQAAAAB", - "xdr": "AAAABgAAAAAAAAABn4yVRAXOeXa1t1POzdT8tEcNP55alAOrUOq9vJIRJeIAAAAUAAAAAQAAABMAAAAA5DNtbckOGVRsNVb8L7X/lIhAOy2o5G6GkLKXvc7W8foAAAAA", - "lastModifiedLedgerSeq": "261603" - } - ], - "latestLedger": 262322 - } -} -``` - -#### Request the `ContractCode` Using the Retrieved `LedgerKey` +#### 2. 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. -##### Python + ```python from stellar_sdk import xdr -def get_ledger_key_wasm_id(contract_code_ledger_entry_data: str) -> str: - # First, we dig the wasm_id hash out of the xdr we received from RPC - contract_code_wasm_hash = xdr.LedgerEntryData.from_xdr( - contract_code_ledger_entry_data - ).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=contract_code_wasm_hash - ), - ) - return ledger_key.to_xdr() - -print( - get_ledger_key_wasm_id( - "AAAABgAAAAAAAAABn4yVRAXOeXa1t1POzdT8tEcNP55alAOrUOq9vJIRJeIAAAAUAAAAAQAAABMAAAAA5DNtbckOGVRsNVb8L7X/lIhAOy2o5G6GkLKXvc7W8foAAAAA" - ) -) -# OUTPUT: AAAAB+QzbW3JDhlUbDVW/C+1/5SIQDstqORuhpCyl73O1vH6 +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 ``` -##### JavaScript - -```javascript +```typescript import { xdr } from "@stellar/stellar-sdk"; -function getLedgerKeyWasmId(contractCodeLedgerEntryData) { - const entry = xdr.LedgerEntryData.fromXDR( - contractCodeLedgerEntryData, - "base64", - ); - - const wasmHash = entry - .contractData() - .val() - .instance() - .executable() - .wasmHash(); +function getLedgerKeyWasmId( + contractData: xdr.ContractDataEntry, +): xdr.LedgerKey { + const wasmHash = contractData.val().instance().executable().wasmHash(); - let ledgerKey = xdr.LedgerKey.contractCode( + return xdr.LedgerKey.contractCode( new xdr.LedgerKeyContractCode({ hash: wasmHash, }), ); - - return ledgerKey.toXDR("base64"); } +``` -console.log( - getLedgerKeyWasmId( - "AAAABgAAAAAAAAABn4yVRAXOeXa1t1POzdT8tEcNP55alAOrUOq9vJIRJeIAAAAUAAAAAQAAABMAAAAA5DNtbckOGVRsNVb8L7X/lIhAOy2o5G6GkLKXvc7W8foAAAAA", - ), -); -// OUTPUT: AAAAB+QzbW3JDhlUbDVW/C+1/5SIQDstqORuhpCyl73O1vH6 + + +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 `getLedgerEntries`. In that response we will get a `LedgerEntryData` corresponding to a `ContractCodeEntry` which will contain the actual, deployed, real-life contract byte-code: + + + +```typescript +const theHashData: xdr.ContractDataEntry = await getLedgerEntries( + getLedgerKeyContractCode("C..."), +).entries[0].contractData(); + +const theCode: Buffer = await getLedgerEntries(getLedgerKeyWasmId(theHashData)) + .entries[0].contractCode() + .code(); ``` -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 Stellar-RPC endpoint. + + +## Actually fetching the ledger entry data + +Once we've learned to _build_ and _parse_ these (which we've done above at length), the process for actually fetching them is always identical. If you know the type of key you fetched, you apply the accessor method accordingly once you've received them from the `getLedgerEntries` method: + + + +```typescript +const s = new Server("https://soroban-testnet.stellar.org"); + +// assume key1 is an account, key2 is a trustline, and key3 is contract data +const keys = await s.getLedgerEntries(key1, key2, key3); + +const account = keys.entries[0].account(); +const contractData = keys.entries[2].contractData(); +const contractCode = keys.entries[1].contractCode(); +``` ```json { "jsonrpc": "2.0", - "id": 8675309, + "id": 12345, "method": "getLedgerEntries", "params": { - "keys": ["AAAAB+QzbW3JDhlUbDVW/C+1/5SIQDstqORuhpCyl73O1vH6"] + "keys": [ + "AAAAB+QzbW3JDhlUbDVW/C+1/5SIQDstqORuhpCyl73O1vH6", + "AAAABgAAAAGfjJVEBc55drW3U87N1Py0Rw0/nlqUA6tQ6r28khEl4gAAABQAAAAB" + "AAAABgAAAAAAAAABn4yVRAXOeXa1t1POzdT8tEcNP55alAOrUOq9vJIRJeIAAAAUAAAAAQAAABMAAAAA5DNtbckOGVRsNVb8L7X/lIhAOy2o5G6GkLKXvc7W8foAAAAA" + ] } } ``` -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 Lab]. + -```json -{ - "jsonrpc": "2.0", - "id": 8675309, - "result": { - "entries": [ - { - "key": "AAAAB+QzbW3JDhlUbDVW/C+1/5SIQDstqORuhpCyl73O1vH6", - "xdr": "AAAABwAAAADkM21tyQ4ZVGw1Vvwvtf+UiEA7LajkboaQspe9ztbx+gAAAkgAYXNtAQAAAAEVBGACfn4BfmADfn5+AX5gAAF+YAAAAhkEAWwBMAAAAWwBMQAAAWwBXwABAWwBOAAAAwUEAgMDAwUDAQAQBhkDfwFBgIDAAAt/AEGAgMAAC38AQYCAwAALBzUFBm1lbW9yeQIACWluY3JlbWVudAAEAV8ABwpfX2RhdGFfZW5kAwELX19oZWFwX2Jhc2UDAgqnAQSSAQIBfwF+QQAhAAJAAkACQEKOutCvhtQ5QgEQgICAgABCAVINAEKOutCvhtQ5QgEQgYCAgAAiAUL/AYNCBFINASABQiCIpyEACyAAQQFqIgBFDQFCjrrQr4bUOSAArUIghkIEhCIBQgEQgoCAgAAaQoSAgICgBkKEgICAwAwQg4CAgAAaIAEPCwAACxCFgICAAAALCQAQhoCAgAAACwQAAAALAgALAHMOY29udHJhY3RzcGVjdjAAAAAAAAAAQEluY3JlbWVudCBpbmNyZW1lbnRzIGFuIGludGVybmFsIGNvdW50ZXIsIGFuZCByZXR1cm5zIHRoZSB2YWx1ZS4AAAAJaW5jcmVtZW50AAAAAAAAAAAAAAEAAAAEAB4RY29udHJhY3RlbnZtZXRhdjAAAAAAAAAAFAAAAAAAbw5jb250cmFjdG1ldGF2MAAAAAAAAAAFcnN2ZXIAAAAAAAAGMS43Ni4wAAAAAAAAAAAACHJzc2RrdmVyAAAALzIwLjMuMSNiYTA0NWE1N2FmOTcxZmM4M2U0NzU3NDZiNTlhNTAzYjdlZjQxNjQ5AA==", - "lastModifiedLedgerSeq": 368441, - "liveUntilLedgerSeq": 2442040 - } - ], - "latestLedger": 370940 - } -} -``` +Then you can inspect them accordingly. Each of the above entries follows the XDR for that `LedgerEntryData` structure precisely. For example, the `AccountEntry` is in [`Stellar-ledger-entries.x#L191`](https://github.com/stellar/stellar-xdr/blob/529d5176f24c73eeccfa5eba481d4e89c19b1181/Stellar-ledger-entries.x#L191) and you can use `.seqNum()` to access its current sequence number, as we've shown. In JavaScript, you can see the appropriate methods in the [type definition](https://github.com/stellar/js-stellar-base/blob/6930a70d7fbde675514b5933baff605d97453ba7/types/curr.d.ts#L3034). [`increment` example contract]: ../../../../build/smart-contracts/getting-started/storing-data ["View XDR" page of the Stellar Lab]: https://lab.stellar.org/xdr/view?$=network$id=testnet&label=Testnet&horizonUrl=https:////horizon-testnet.stellar.org&rpcUrl=https:////soroban-testnet.stellar.org&passphrase=Test%20SDF%20Network%20/;%20September%202015;; From 8e8448bbcb05e30221927c9132c80b279e61eda4 Mon Sep 17 00:00:00 2001 From: George Date: Fri, 25 Oct 2024 12:32:17 -0700 Subject: [PATCH 02/13] Fixup all links --- .../rpc/api-reference/methods/getLedgerEntries.mdx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/data/rpc/api-reference/methods/getLedgerEntries.mdx b/docs/data/rpc/api-reference/methods/getLedgerEntries.mdx index 385614900..5019ee180 100644 --- a/docs/data/rpc/api-reference/methods/getLedgerEntries.mdx +++ b/docs/data/rpc/api-reference/methods/getLedgerEntries.mdx @@ -19,11 +19,11 @@ The `getLedgerEntries` method returns the "values" (or "entries") for a given se The source of truth should always be the XDR defined in the protocol. `LedgerKey`s are a union type defined in [Stellar-ledger-entries.x](https://github.com/stellar/stellar-xdr/blob/529d5176f24c73eeccfa5eba481d4e89c19b1181/Stellar-ledger-entries.x#L600). There are 10 different forms a ledger key can take: 1. Account: holistically defines a Stellar account, including its balance, signers, etc. -2. Trustline: defines a balance line to a non-native asset issued on the network (see [`changeTrustOp`](TODO)) -3. Offer: defines an offer made on the Stellar DEX (see e.g., [`manageOfferOp`](TODO)) -4. Data: defines key-value data entries attached to an account (see [`manageDataOp`](TODO)) -5. Claimable Balance: defines a balance that may or may not actively be claimable (see [`createClaimableBalanceOp`](TODO)) -6. Liquidity Pool: defines the configuration of a native constant liquidity pool between two assets (see [``]()) +2. Trustline: defines a balance line to a non-native asset issued on the network (see [`changeTrustOp`](https://developers.stellar.org/docs/learn/fundamentals/transactions/list-of-operations#change-trust)) +3. Offer: defines an offer made on the Stellar DEX (see [Liquidity on Stellar`](https://developers.stellar.org/docs/learn/encyclopedia/sdex/liquidity-on-stellar-sdex-liquidity-pools)) +4. Data: defines key-value data entries attached to an account (see [`manageDataOp`](https://developers.stellar.org/docs/learn/fundamentals/transactions/list-of-operations#manage-data)) +5. Claimable Balance: defines a balance that may or may not actively be claimable (see [Claimable Balances](https://developers.stellar.org/docs/learn/encyclopedia/transactions-specialized/claimable-balances)) +6. Liquidity Pool: defines the configuration of a native constant liquidity pool between two assets (see [Liquidity on Stellar](https://developers.stellar.org/docs/learn/encyclopedia/sdex/liquidity-on-stellar-sdex-liquidity-pools)) 7. Contract Data: defines a piece of data being stored in a contract under a key 8. Contract Code: defines the Wasm bytecode of a contract 9. Config Setting: defines the currently active network configuration From 1fb9ba022b9ba6f807cd92ec7de5fc2f77a46890 Mon Sep 17 00:00:00 2001 From: George Date: Fri, 25 Oct 2024 12:34:28 -0700 Subject: [PATCH 03/13] More formatting --- .../methods/getLedgerEntries.mdx | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/data/rpc/api-reference/methods/getLedgerEntries.mdx b/docs/data/rpc/api-reference/methods/getLedgerEntries.mdx index 5019ee180..820e4abde 100644 --- a/docs/data/rpc/api-reference/methods/getLedgerEntries.mdx +++ b/docs/data/rpc/api-reference/methods/getLedgerEntries.mdx @@ -18,18 +18,18 @@ The `getLedgerEntries` method returns the "values" (or "entries") for a given se The source of truth should always be the XDR defined in the protocol. `LedgerKey`s are a union type defined in [Stellar-ledger-entries.x](https://github.com/stellar/stellar-xdr/blob/529d5176f24c73eeccfa5eba481d4e89c19b1181/Stellar-ledger-entries.x#L600). There are 10 different forms a ledger key can take: -1. Account: holistically defines a Stellar account, including its balance, signers, etc. -2. Trustline: defines a balance line to a non-native asset issued on the network (see [`changeTrustOp`](https://developers.stellar.org/docs/learn/fundamentals/transactions/list-of-operations#change-trust)) -3. Offer: defines an offer made on the Stellar DEX (see [Liquidity on Stellar`](https://developers.stellar.org/docs/learn/encyclopedia/sdex/liquidity-on-stellar-sdex-liquidity-pools)) -4. Data: defines key-value data entries attached to an account (see [`manageDataOp`](https://developers.stellar.org/docs/learn/fundamentals/transactions/list-of-operations#manage-data)) -5. Claimable Balance: defines a balance that may or may not actively be claimable (see [Claimable Balances](https://developers.stellar.org/docs/learn/encyclopedia/transactions-specialized/claimable-balances)) -6. Liquidity Pool: defines the configuration of a native constant liquidity pool between two assets (see [Liquidity on Stellar](https://developers.stellar.org/docs/learn/encyclopedia/sdex/liquidity-on-stellar-sdex-liquidity-pools)) -7. Contract Data: defines a piece of data being stored in a contract under a key -8. Contract Code: defines the Wasm bytecode of a contract -9. Config Setting: defines the currently active network configuration -10. Ttl: defines the time-to-live of an associated contract data or code entry - -We're going to focus on a subset of these for maximum value. +1. **Account:** holistically defines a Stellar account, including its balance, signers, etc. +2. **Trustline:** defines a balance line to a non-native asset issued on the network (see [`changeTrustOp`](https://developers.stellar.org/docs/learn/fundamentals/transactions/list-of-operations#change-trust)) +3. **Offer:** defines an offer made on the Stellar DEX (see [Liquidity on Stellar`](https://developers.stellar.org/docs/learn/encyclopedia/sdex/liquidity-on-stellar-sdex-liquidity-pools)) +4. **Account Data:** defines key-value data entries attached to an account (see [`manageDataOp`](https://developers.stellar.org/docs/learn/fundamentals/transactions/list-of-operations#manage-data)) +5. **Claimable Balance:** defines a balance that may or may not actively be claimable (see [Claimable Balances](https://developers.stellar.org/docs/learn/encyclopedia/transactions-specialized/claimable-balances)) +6. **Liquidity Pool:** defines the configuration of a native constant liquidity pool between two assets (see [Liquidity on Stellar](https://developers.stellar.org/docs/learn/encyclopedia/sdex/liquidity-on-stellar-sdex-liquidity-pools)) +7. **Contract Data:** defines a piece of data being stored in a contract under a key +8. **Contract Code:** defines the Wasm bytecode of a contract +9. **Config Setting:** defines the currently active network configuration +10. **TTL:** defines the time-to-live of an associated contract data or code entry + +We're going to focus on a subset of these for maximum value, but once you understand how to build and parse some keys and entries, you can extrapolate to all of them. ### Accounts From 9c8dff6a1134b935f4d1cab9ce5cc1e0e74d7bd0 Mon Sep 17 00:00:00 2001 From: George Date: Fri, 25 Oct 2024 12:41:00 -0700 Subject: [PATCH 04/13] Run formatter, add links --- docs/data/rpc/api-reference/methods/getLedgerEntries.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/data/rpc/api-reference/methods/getLedgerEntries.mdx b/docs/data/rpc/api-reference/methods/getLedgerEntries.mdx index 820e4abde..a04f2afcc 100644 --- a/docs/data/rpc/api-reference/methods/getLedgerEntries.mdx +++ b/docs/data/rpc/api-reference/methods/getLedgerEntries.mdx @@ -18,9 +18,9 @@ The `getLedgerEntries` method returns the "values" (or "entries") for a given se The source of truth should always be the XDR defined in the protocol. `LedgerKey`s are a union type defined in [Stellar-ledger-entries.x](https://github.com/stellar/stellar-xdr/blob/529d5176f24c73eeccfa5eba481d4e89c19b1181/Stellar-ledger-entries.x#L600). There are 10 different forms a ledger key can take: -1. **Account:** holistically defines a Stellar account, including its balance, signers, etc. +1. **Account:** holistically defines a Stellar account, including its balance, signers, etc. (see [Accounts](https://developers.stellar.org/docs/learn/fundamentals/stellar-data-structures/accounts)) 2. **Trustline:** defines a balance line to a non-native asset issued on the network (see [`changeTrustOp`](https://developers.stellar.org/docs/learn/fundamentals/transactions/list-of-operations#change-trust)) -3. **Offer:** defines an offer made on the Stellar DEX (see [Liquidity on Stellar`](https://developers.stellar.org/docs/learn/encyclopedia/sdex/liquidity-on-stellar-sdex-liquidity-pools)) +3. **Offer:** defines an offer made on the Stellar DEX (see [Liquidity on Stellar](https://developers.stellar.org/docs/learn/encyclopedia/sdex/liquidity-on-stellar-sdex-liquidity-pools)) 4. **Account Data:** defines key-value data entries attached to an account (see [`manageDataOp`](https://developers.stellar.org/docs/learn/fundamentals/transactions/list-of-operations#manage-data)) 5. **Claimable Balance:** defines a balance that may or may not actively be claimable (see [Claimable Balances](https://developers.stellar.org/docs/learn/encyclopedia/transactions-specialized/claimable-balances)) 6. **Liquidity Pool:** defines the configuration of a native constant liquidity pool between two assets (see [Liquidity on Stellar](https://developers.stellar.org/docs/learn/encyclopedia/sdex/liquidity-on-stellar-sdex-liquidity-pools)) From 657e0db59e4d24bd7ce4cf6542a5e6eceb7eaba7 Mon Sep 17 00:00:00 2001 From: George Date: Mon, 28 Oct 2024 16:52:57 -0700 Subject: [PATCH 05/13] Add CLI usage, cleanup --- .../methods/getLedgerEntries.mdx | 30 ++++++++++++++----- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/docs/data/rpc/api-reference/methods/getLedgerEntries.mdx b/docs/data/rpc/api-reference/methods/getLedgerEntries.mdx index a04f2afcc..3fd1a1791 100644 --- a/docs/data/rpc/api-reference/methods/getLedgerEntries.mdx +++ b/docs/data/rpc/api-reference/methods/getLedgerEntries.mdx @@ -3,6 +3,7 @@ hide_title: true description: Returns ledger entries --- +import { CodeExample } from "@site/src/components/CodeExample"; import { RpcMethod } from "@site/src/components/RpcMethod"; import rpcSpec from "@site/static/stellar-rpc.openrpc.json"; @@ -184,17 +185,17 @@ Thus, fetching the contract code is a two-step process: 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 - ) + 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" + "CCPYZFKEAXHHS5VVW5J45TOU7S2EODJ7TZNJIA5LKDVL3PESCES6FNCI" )) ``` @@ -312,5 +313,18 @@ const contractCode = keys.entries[1].contractCode(); Then you can inspect them accordingly. Each of the above entries follows the XDR for that `LedgerEntryData` structure precisely. For example, the `AccountEntry` is in [`Stellar-ledger-entries.x#L191`](https://github.com/stellar/stellar-xdr/blob/529d5176f24c73eeccfa5eba481d4e89c19b1181/Stellar-ledger-entries.x#L191) and you can use `.seqNum()` to access its current sequence number, as we've shown. In JavaScript, you can see the appropriate methods in the [type definition](https://github.com/stellar/js-stellar-base/blob/6930a70d7fbde675514b5933baff605d97453ba7/types/curr.d.ts#L3034). +## Viewing and understanding XDR + +If you don't want to parse the XDR out programmatically, you can also leverage both the [Stellar CLI](https://developers.stellar.org/docs/tools/developer-tools/cli/stellar-cli) and the [Stellar Lab](https://lab.stellar.org/xdr/view) to get a human-readable view of ledger keys and entries. For example, + +```bash +echo 'AAAAAAAAAAAL76GC5jcgEGfLG9+nptaB9m+R44oweeN3EcqhstdzhQ==' | stellar xdr decode --type LedgerKey | jq +{ + "account": { + "account_id": "GAF67IMC4Y3SAEDHZMN57J5G22A7M34R4OFDA6PDO4I4VINS25ZYLBZZ" + } +} +``` + [`increment` example contract]: ../../../../build/smart-contracts/getting-started/storing-data ["View XDR" page of the Stellar Lab]: https://lab.stellar.org/xdr/view?$=network$id=testnet&label=Testnet&horizonUrl=https:////horizon-testnet.stellar.org&rpcUrl=https:////soroban-testnet.stellar.org&passphrase=Test%20SDF%20Network%20/;%20September%202015;; From 338693c54bd70fa56a5c0abf3e5020b64c7b96fb Mon Sep 17 00:00:00 2001 From: George Date: Mon, 28 Oct 2024 17:19:49 -0700 Subject: [PATCH 06/13] Fix lack of closing tag oops --- docs/data/rpc/api-reference/methods/getLedgerEntries.mdx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/data/rpc/api-reference/methods/getLedgerEntries.mdx b/docs/data/rpc/api-reference/methods/getLedgerEntries.mdx index 3fd1a1791..0187c4953 100644 --- a/docs/data/rpc/api-reference/methods/getLedgerEntries.mdx +++ b/docs/data/rpc/api-reference/methods/getLedgerEntries.mdx @@ -165,6 +165,8 @@ const ledgerKey = getLedgerKeySymbol( ); ``` + + ### Contract Wasm Code To understand this, we need a handle on how smart contract deployment works: From a30fe6492b3e08965f2d4b83f1fd85a33ac552a4 Mon Sep 17 00:00:00 2001 From: George Date: Fri, 29 Nov 2024 21:28:03 -0800 Subject: [PATCH 07/13] Fixup sloppy merge --- docs/build/guides/testing/unit-tests.mdx | 9 +++++++++ .../rpc/api-reference/methods/getLedgerEntries.mdx | 10 ++-------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/docs/build/guides/testing/unit-tests.mdx b/docs/build/guides/testing/unit-tests.mdx index 0deaab4b7..e4d22bc27 100644 --- a/docs/build/guides/testing/unit-tests.mdx +++ b/docs/build/guides/testing/unit-tests.mdx @@ -71,4 +71,13 @@ The `Env` created at the beginning of the test is not a simulation of the Soroba ::: +It's a simple test, but it's a complete test. There's a full environment setup, used, and torn down in the test, and it happens fast. The Rust test harness runs all the tests for a contract in parallel and each will have its own isolated contract environment. + +Most tests, even integration tests and fuzz tests, will look very similar to this unit test. They'll do four things: + +1. Create an environment, the `Env`. +2. Register the contract(s) to be tested. +3. Invoke functions using a client. +4. Assert the outcome. + [increment contract]: https://github.com/stellar/soroban-examples/blob/main/increment/src/lib.rs diff --git a/docs/data/rpc/api-reference/methods/getLedgerEntries.mdx b/docs/data/rpc/api-reference/methods/getLedgerEntries.mdx index 0187c4953..972f95b4c 100644 --- a/docs/data/rpc/api-reference/methods/getLedgerEntries.mdx +++ b/docs/data/rpc/api-reference/methods/getLedgerEntries.mdx @@ -265,8 +265,6 @@ function getLedgerKeyWasmId( 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 `getLedgerEntries`. In that response we will get a `LedgerEntryData` corresponding to a `ContractCodeEntry` which will contain the actual, deployed, real-life contract byte-code: - - ```typescript const theHashData: xdr.ContractDataEntry = await getLedgerEntries( getLedgerKeyContractCode("C..."), @@ -277,14 +275,10 @@ const theCode: Buffer = await getLedgerEntries(getLedgerKeyWasmId(theHashData)) .code(); ``` - - ## Actually fetching the ledger entry data Once we've learned to _build_ and _parse_ these (which we've done above at length), the process for actually fetching them is always identical. If you know the type of key you fetched, you apply the accessor method accordingly once you've received them from the `getLedgerEntries` method: - - ```typescript const s = new Server("https://soroban-testnet.stellar.org"); @@ -296,6 +290,8 @@ const contractData = keys.entries[2].contractData(); const contractCode = keys.entries[1].contractCode(); ``` +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 Stellar-RPC endpoint. + ```json { "jsonrpc": "2.0", @@ -311,8 +307,6 @@ const contractCode = keys.entries[1].contractCode(); } ``` - - Then you can inspect them accordingly. Each of the above entries follows the XDR for that `LedgerEntryData` structure precisely. For example, the `AccountEntry` is in [`Stellar-ledger-entries.x#L191`](https://github.com/stellar/stellar-xdr/blob/529d5176f24c73eeccfa5eba481d4e89c19b1181/Stellar-ledger-entries.x#L191) and you can use `.seqNum()` to access its current sequence number, as we've shown. In JavaScript, you can see the appropriate methods in the [type definition](https://github.com/stellar/js-stellar-base/blob/6930a70d7fbde675514b5933baff605d97453ba7/types/curr.d.ts#L3034). ## Viewing and understanding XDR From 424b47d94cc258bebace3713dc8f77037fca4de0 Mon Sep 17 00:00:00 2001 From: George Date: Thu, 6 Mar 2025 07:34:11 -0800 Subject: [PATCH 08/13] Clarity, headings, tagged links, etc. --- .husky/pre-commit | 10 +++++----- docs/build/guides/testing/unit-tests.mdx | 9 --------- .../rpc/api-reference/methods/getLedgerEntries.mdx | 14 ++++++++------ 3 files changed, 13 insertions(+), 20 deletions(-) diff --git a/.husky/pre-commit b/.husky/pre-commit index 45f8b3033..4b17bc501 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,5 +1,5 @@ -G='\033[0;32m' -P='\033[0;35m' -CLEAN='\033[0;0m' - -yarn run check:mdx || (echo -e "${G}Hint:${CLEAN} execute ${P}yarn run format:mdx${CLEAN} to format files" && exit 1) +G='\033[0;32m' +P='\033[0;35m' +CLEAN='\033[0;0m' + +yarn run check:mdx || (echo -e "${G}Hint:${CLEAN} execute ${P}yarn run format:mdx${CLEAN} to format files" && exit 1) diff --git a/docs/build/guides/testing/unit-tests.mdx b/docs/build/guides/testing/unit-tests.mdx index e4d22bc27..0deaab4b7 100644 --- a/docs/build/guides/testing/unit-tests.mdx +++ b/docs/build/guides/testing/unit-tests.mdx @@ -71,13 +71,4 @@ The `Env` created at the beginning of the test is not a simulation of the Soroba ::: -It's a simple test, but it's a complete test. There's a full environment setup, used, and torn down in the test, and it happens fast. The Rust test harness runs all the tests for a contract in parallel and each will have its own isolated contract environment. - -Most tests, even integration tests and fuzz tests, will look very similar to this unit test. They'll do four things: - -1. Create an environment, the `Env`. -2. Register the contract(s) to be tested. -3. Invoke functions using a client. -4. Assert the outcome. - [increment contract]: https://github.com/stellar/soroban-examples/blob/main/increment/src/lib.rs diff --git a/docs/data/rpc/api-reference/methods/getLedgerEntries.mdx b/docs/data/rpc/api-reference/methods/getLedgerEntries.mdx index 972f95b4c..d9a681fd9 100644 --- a/docs/data/rpc/api-reference/methods/getLedgerEntries.mdx +++ b/docs/data/rpc/api-reference/methods/getLedgerEntries.mdx @@ -11,13 +11,15 @@ import rpcSpec from "@site/static/stellar-rpc.openrpc.json"; method={rpcSpec.methods.filter((meth) => meth.name === "getLedgerEntries")[0]} /> -The Stellar ledger is, on some level, essentially a key-value store. The keys are `LedgerKey`s and the values are `LedgerEntryData`s in the XDR. An interesting product of the store's internal design is that the key is a _subset_ of the entry: we'll see more of this later. +# Building ledger keys -The `getLedgerEntries` method returns the "values" (or "entries") for a given set of "keys". `LedgerKey`s come in a lot of forms, and we'll go over the valuable ones on this page alongside tutorials on how to build and use them. +The Stellar ledger is, on some level, essentially a key-value store. The keys are `LedgerKey`s and the values are `LedgerEntry`s in the XDR. An interesting product of the store's internal design is that the key is a _subset_ of the entry: we'll see more of this later. + +The `getLedgerEntries` method returns the "values" (or "entries") for a given set of "keys". `LedgerKey`s come in a lot of forms, and we'll go over the commonly used ones on this page alongside tutorials on how to build and use them. ## Types of `LedgerKey`s -The source of truth should always be the XDR defined in the protocol. `LedgerKey`s are a union type defined in [Stellar-ledger-entries.x](https://github.com/stellar/stellar-xdr/blob/529d5176f24c73eeccfa5eba481d4e89c19b1181/Stellar-ledger-entries.x#L600). There are 10 different forms a ledger key can take: +The source of truth should always be the XDR defined in the protocol. `LedgerKey`s are a union type defined in [Stellar-ledger-entries.x](https://github.com/stellar/stellar-xdr/blob/v22.0/Stellar-ledger-entries.x#L600). There are 10 different forms a ledger key can take: 1. **Account:** holistically defines a Stellar account, including its balance, signers, etc. (see [Accounts](https://developers.stellar.org/docs/learn/fundamentals/stellar-data-structures/accounts)) 2. **Trustline:** defines a balance line to a non-native asset issued on the network (see [`changeTrustOp`](https://developers.stellar.org/docs/learn/fundamentals/transactions/list-of-operations#change-trust)) @@ -119,7 +121,7 @@ console.log( ### Contract Data -Suppose we've deployed the [`increment` example contract] and want to find out what value is stored in the `COUNTER` ledger key. To build the key, +Suppose we've deployed the [`increment` example contract] and want to find out what value is stored in the `COUNTER` ledger key. To build the key: @@ -307,14 +309,14 @@ Now, finally we have a `LedgerKey` that correspond to the Wasm byte-code that ha } ``` -Then you can inspect them accordingly. Each of the above entries follows the XDR for that `LedgerEntryData` structure precisely. For example, the `AccountEntry` is in [`Stellar-ledger-entries.x#L191`](https://github.com/stellar/stellar-xdr/blob/529d5176f24c73eeccfa5eba481d4e89c19b1181/Stellar-ledger-entries.x#L191) and you can use `.seqNum()` to access its current sequence number, as we've shown. In JavaScript, you can see the appropriate methods in the [type definition](https://github.com/stellar/js-stellar-base/blob/6930a70d7fbde675514b5933baff605d97453ba7/types/curr.d.ts#L3034). +Then you can inspect them accordingly. Each of the above entries follows the XDR for that `LedgerEntryData` structure precisely. For example, the `AccountEntry` is in [`Stellar-ledger-entries.x#L191`](https://github.com/stellar/stellar-xdr/blob/v22.0/Stellar-ledger-entries.x#L191) and you can use `.seqNum()` to access its current sequence number, as we've shown. In JavaScript, you can see the appropriate methods in the [type definition](https://github.com/stellar/js-stellar-base/blob/6930a70d7fbde675514b5933baff605d97453ba7/types/curr.d.ts#L3034). ## Viewing and understanding XDR If you don't want to parse the XDR out programmatically, you can also leverage both the [Stellar CLI](https://developers.stellar.org/docs/tools/developer-tools/cli/stellar-cli) and the [Stellar Lab](https://lab.stellar.org/xdr/view) to get a human-readable view of ledger keys and entries. For example, ```bash -echo 'AAAAAAAAAAAL76GC5jcgEGfLG9+nptaB9m+R44oweeN3EcqhstdzhQ==' | stellar xdr decode --type LedgerKey | jq +echo 'AAAAAAAAAAAL76GC5jcgEGfLG9+nptaB9m+R44oweeN3EcqhstdzhQ==' | stellar xdr decode --type LedgerKey --output json-formatted { "account": { "account_id": "GAF67IMC4Y3SAEDHZMN57J5G22A7M34R4OFDA6PDO4I4VINS25ZYLBZZ" From 43e280be8c469e62b7cbbae3bed8a5a5c00d8e7f Mon Sep 17 00:00:00 2001 From: George Date: Fri, 7 Mar 2025 10:29:16 -0800 Subject: [PATCH 09/13] Feedback: better naming, js -> ts --- .../api-reference/methods/getLedgerEntries.mdx | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/docs/data/rpc/api-reference/methods/getLedgerEntries.mdx b/docs/data/rpc/api-reference/methods/getLedgerEntries.mdx index d9a681fd9..7cf113061 100644 --- a/docs/data/rpc/api-reference/methods/getLedgerEntries.mdx +++ b/docs/data/rpc/api-reference/methods/getLedgerEntries.mdx @@ -147,15 +147,17 @@ print( ) ``` -```js +```typescript import { xdr, Address } from "@stellar/stellar-sdk"; -const getLedgerKeySymbol = (contractId, symbolText) => { +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), - // or, possibly, .temporary(), depending on your contract + // The increment contract stores its state in persistent storage, + // but other contracts may use temporary storage + // (xdr.ContractDataDurability.temporary()). durability: xdr.ContractDataDurability.persistent(), }), ); @@ -174,7 +176,7 @@ const ledgerKey = getLedgerKeySymbol( To understand this, we need a handle on how smart contract deployment works: - When you deploy a contract, first the code is "installed" (i.e. uploaded onto the blockchain), creating a `LedgerEntry` with the Wasm byte-code that can be uniquely identified by its hash (that is, the hash of the uploaded code itself). -- Then, when a contract _instance_ is "deployed," we create a `LedgerEntry` with a reference to that code's hash. This means many contracts can point to the same Wasm code. +- Then, when a contract _instance_ is "instantiated," we create a `LedgerEntry` with a reference to that code's hash. This means many contracts can point to the same Wasm code. Thus, fetching the contract code is a two-step process: @@ -285,11 +287,11 @@ Once we've learned to _build_ and _parse_ these (which we've done above at lengt const s = new Server("https://soroban-testnet.stellar.org"); // assume key1 is an account, key2 is a trustline, and key3 is contract data -const keys = await s.getLedgerEntries(key1, key2, key3); +const response = await s.getLedgerEntries(key1, key2, key3); -const account = keys.entries[0].account(); -const contractData = keys.entries[2].contractData(); -const contractCode = keys.entries[1].contractCode(); +const account = response.entries[0].account(); +const contractData = response.entries[2].contractData(); +const contractCode = response.entries[1].contractCode(); ``` 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 Stellar-RPC endpoint. From 722669a572003560e742f4775f1c570db1a1eb03 Mon Sep 17 00:00:00 2001 From: George Date: Fri, 7 Mar 2025 10:29:59 -0800 Subject: [PATCH 10/13] Run linter --- docs/data/rpc/api-reference/methods/getLedgerEntries.mdx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/data/rpc/api-reference/methods/getLedgerEntries.mdx b/docs/data/rpc/api-reference/methods/getLedgerEntries.mdx index 7cf113061..05dec30a9 100644 --- a/docs/data/rpc/api-reference/methods/getLedgerEntries.mdx +++ b/docs/data/rpc/api-reference/methods/getLedgerEntries.mdx @@ -150,7 +150,10 @@ print( ```typescript import { xdr, Address } from "@stellar/stellar-sdk"; -const getLedgerKeySymbol = (contractId: string, symbolText: string): xdr.LedgerKey => { +const getLedgerKeySymbol = ( + contractId: string, + symbolText: string, +): xdr.LedgerKey => { return xdr.LedgerKey.contractData( new xdr.LedgerKeyContractData({ contract: new Address(contractId).toScAddress(), From b00970bb3f6bf700472c8876a33d60a69a88d099 Mon Sep 17 00:00:00 2001 From: George Date: Fri, 7 Mar 2025 10:35:05 -0800 Subject: [PATCH 11/13] Add cross-refs to the protocol definitions --- docs/data/rpc/api-reference/methods/getLedgerEntries.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/data/rpc/api-reference/methods/getLedgerEntries.mdx b/docs/data/rpc/api-reference/methods/getLedgerEntries.mdx index 05dec30a9..5a52bfce1 100644 --- a/docs/data/rpc/api-reference/methods/getLedgerEntries.mdx +++ b/docs/data/rpc/api-reference/methods/getLedgerEntries.mdx @@ -13,9 +13,9 @@ import rpcSpec from "@site/static/stellar-rpc.openrpc.json"; # Building ledger keys -The Stellar ledger is, on some level, essentially a key-value store. The keys are `LedgerKey`s and the values are `LedgerEntry`s in the XDR. An interesting product of the store's internal design is that the key is a _subset_ of the entry: we'll see more of this later. +The Stellar ledger is, on some level, essentially a key-value store. The keys are instances of [`LedgerKey`](https://github.com/stellar/stellar-xdr/blob/v22.0/Stellar-ledger-entries.x#L600) and the values are instances of [`LedgerEntry`](https://github.com/stellar/stellar-xdr/blob/v22.0/Stellar-ledger-entries.x#L560). An interesting product of the store's internal design is that the key is a _subset_ of the entry: we'll see more of this later. -The `getLedgerEntries` method returns the "values" (or "entries") for a given set of "keys". `LedgerKey`s come in a lot of forms, and we'll go over the commonly used ones on this page alongside tutorials on how to build and use them. +The `getLedgerEntries` method returns the "values" (or "entries") for a given set of "keys". Ledger keys come in a lot of forms, and we'll go over the commonly used ones on this page alongside tutorials on how to build and use them. ## Types of `LedgerKey`s From ba98ca94c2e658724ecb81c1fa2a384af97f4d21 Mon Sep 17 00:00:00 2001 From: George Date: Fri, 7 Mar 2025 10:39:19 -0800 Subject: [PATCH 12/13] Reword ledger entry fetch description --- openrpc/src/stellar-rpc/methods/getLedgerEntries.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openrpc/src/stellar-rpc/methods/getLedgerEntries.json b/openrpc/src/stellar-rpc/methods/getLedgerEntries.json index 50fc2c688..0437b41f2 100644 --- a/openrpc/src/stellar-rpc/methods/getLedgerEntries.json +++ b/openrpc/src/stellar-rpc/methods/getLedgerEntries.json @@ -1,7 +1,7 @@ { "name": "getLedgerEntries", "summary": "returns ledger entries", - "description": "For reading the current value of ledger entries directly.\n\nThis method enables the retrieval of various ledger states, such as 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`.\n\nTo fetch contract wasm byte-code, use the ContractCode ledger entry key.", + "description": "For reading the current value of ledger entries directly.\n\nThis 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`.\n\nTo fetch contract wasm byte-code, use the ContractCode ledger entry key.", "externalDocs": { "url": "https://developers.stellar.org/docs/data/rpc/api-reference/methods/getLedgerEntries" }, From 4e1b673b781af451bb8d4df70cb9fe8199d523dd Mon Sep 17 00:00:00 2001 From: George Date: Fri, 7 Mar 2025 12:00:16 -0800 Subject: [PATCH 13/13] Run RPC spec assembler --- static/stellar-rpc.openrpc.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/stellar-rpc.openrpc.json b/static/stellar-rpc.openrpc.json index f3818d8b6..e46edcd8a 100644 --- a/static/stellar-rpc.openrpc.json +++ b/static/stellar-rpc.openrpc.json @@ -688,7 +688,7 @@ { "name": "getLedgerEntries", "summary": "returns ledger entries", - "description": "For reading the current value of ledger entries directly.\n\nThis method enables the retrieval of various ledger states, such as 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`.\n\nTo fetch contract wasm byte-code, use the ContractCode ledger entry key.", + "description": "For reading the current value of ledger entries directly.\n\nThis 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`.\n\nTo fetch contract wasm byte-code, use the ContractCode ledger entry key.", "externalDocs": { "url": "https://developers.stellar.org/docs/data/rpc/api-reference/methods/getLedgerEntries" },